emacs-diffs
[Top][All Lists]
Advanced

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

master 0b63b7e 2/2: Merge branch 'master' of git.sv.gnu.org:/srv/git/ema


From: Michael Albinus
Subject: master 0b63b7e 2/2: Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
Date: Mon, 11 Oct 2021 04:16:59 -0400 (EDT)

branch: master
commit 0b63b7e60ab87debb98bbd95c4b15984e4bba124
Merge: 978e533 005c15c
Author: Michael Albinus <michael.albinus@gmx.de>
Commit: Michael Albinus <michael.albinus@gmx.de>

    Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
---
 admin/make-tarball.txt                             |   6 +
 doc/emacs/anti.texi                                | 198 ++++++------
 doc/emacs/emacs.texi                               |   2 +-
 doc/emacs/frames.texi                              |   4 +-
 doc/emacs/maintaining.texi                         |   2 +-
 doc/lispref/anti.texi                              | 241 +++++++--------
 doc/lispref/elisp.texi                             |   2 +-
 doc/lispref/searching.texi                         |  22 +-
 doc/misc/ert.texi                                  |   2 +-
 doc/misc/mairix-el.texi                            |  12 +
 etc/ERC-NEWS                                       | 181 ++++++++++-
 etc/NEWS                                           |   9 +
 etc/NEWS.28                                        | 284 +++++++----------
 etc/TODO                                           |  19 ++
 lisp/bindings.el                                   |   2 +-
 lisp/emulation/viper-cmd.el                        |  47 ++-
 lisp/emulation/viper-ex.el                         |   1 -
 lisp/emulation/viper-init.el                       |  11 +-
 lisp/emulation/viper-mous.el                       |   5 +-
 lisp/emulation/viper-util.el                       |  47 +--
 lisp/emulation/viper.el                            |   1 -
 lisp/erc/erc-button.el                             |   3 +-
 lisp/erc/erc.el                                    |  36 ++-
 lisp/frame.el                                      |  31 +-
 lisp/gnus/gnus-util.el                             |   3 +-
 lisp/info-look.el                                  |  71 +++++
 lisp/international/characters.el                   |   4 +-
 lisp/ls-lisp.el                                    |   1 +
 lisp/mh-e/mh-acros.el                              |  22 +-
 lisp/mh-e/mh-alias.el                              |  26 +-
 lisp/mh-e/mh-comp.el                               |  20 +-
 lisp/mh-e/mh-compat.el                             | 341 ++++-----------------
 lisp/mh-e/mh-e.el                                  |  51 +--
 lisp/mh-e/mh-folder.el                             | 297 ++++++++----------
 lisp/mh-e/mh-funcs.el                              |   2 +-
 lisp/mh-e/mh-gnus.el                               | 138 +++------
 lisp/mh-e/mh-identity.el                           |   9 +-
 lisp/mh-e/mh-letter.el                             | 138 ++++-----
 lisp/mh-e/mh-limit.el                              |   8 +-
 lisp/mh-e/mh-mime.el                               | 107 +++----
 lisp/mh-e/mh-search.el                             |  99 +++---
 lisp/mh-e/mh-seq.el                                |  13 +-
 lisp/mh-e/mh-show.el                               | 271 ++++++++--------
 lisp/mh-e/mh-speed.el                              |  70 ++---
 lisp/mh-e/mh-thread.el                             |  16 +-
 lisp/mh-e/mh-tool-bar.el                           |  84 +----
 lisp/mh-e/mh-utils.el                              |  43 +--
 lisp/mh-e/mh-xface.el                              |  63 +---
 lisp/obsolete/crisp.el                             |  22 +-
 lisp/obsolete/eudcb-ph.el                          |   4 +-
 lisp/obsolete/fast-lock.el                         |  35 +--
 lisp/obsolete/iswitchb.el                          |  16 +-
 lisp/obsolete/otodo-mode.el                        |   3 +-
 lisp/obsolete/pgg-parse.el                         |   3 +-
 lisp/obsolete/pgg.el                               |   3 +-
 lisp/obsolete/tpu-edt.el                           |  23 +-
 lisp/obsolete/tpu-mapper.el                        |  54 +---
 lisp/progmodes/bug-reference.el                    |   8 +-
 lisp/progmodes/sql.el                              |  26 +-
 lisp/progmodes/xref.el                             | 124 ++++----
 lisp/simple.el                                     |  33 +-
 lisp/subr.el                                       |   9 +-
 lisp/tab-bar.el                                    |  48 +--
 lisp/textmodes/reftex-toc.el                       |   4 +-
 lisp/tool-bar.el                                   |   2 +
 lisp/vc/vc-hg.el                                   |   7 +-
 make-dist                                          |   6 +-
 src/Makefile.in                                    |  11 +-
 src/buffer.c                                       |   2 +-
 src/comp.c                                         |   5 +-
 src/composite.h                                    |   4 +
 src/dispextern.h                                   |   4 +-
 src/keyboard.c                                     |   3 +-
 src/minibuf.c                                      |   6 +-
 src/search.c                                       |  88 +++---
 src/term.c                                         |   2 +-
 .../elisp-mode-resources/simple-shorthand-test.el  |   2 +
 77 files changed, 1594 insertions(+), 2028 deletions(-)

diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt
index ae007d76..2227608 100644
--- a/admin/make-tarball.txt
+++ b/admin/make-tarball.txt
@@ -42,6 +42,12 @@ General steps (for each step, check for possible errors):
     because some of the commands below run Make, so they need
     Makefiles to be present.
 
+    For Emacs 28, and as long as --with-native-compilation is not the
+    default, the tree needs to be configured with native-compilation
+    enabled, to ensure all the pertinent *.elc files will end up in
+    the tarball.  Otherwise, the *.eln files might not build correctly
+    on the user's system.
+
 2.  Regenerate the etc/AUTHORS file:
       M-: (require 'authors) RET
       M-x authors RET
diff --git a/doc/emacs/anti.texi b/doc/emacs/anti.texi
index 49da473..354f20e 100644
--- a/doc/emacs/anti.texi
+++ b/doc/emacs/anti.texi
@@ -4,156 +4,138 @@
 @c See file emacs.texi for copying conditions.
 
 @node Antinews
-@appendix Emacs 26 Antinews
+@appendix Emacs 27 Antinews
 @c Update the emacs.texi Antinews menu entry with the above version number.
 
   For those users who live backwards in time, here is information
-about downgrading to Emacs version 26.3.  We hope you will enjoy the
+about downgrading to Emacs version 27.2.  We hope you will enjoy the
 greater simplicity that results from the absence of many @w{Emacs
 @value{EMACSVER}} features.
 
 @itemize @bullet
 @item
-Emacs no longer uses @acronym{GMP}, the GNU Multiple Precision
-library, and doesn't support Lisp integers greater than
-@code{most-positive-fixnum} or smaller than
-@code{most-negative-fixnum}.  We now have only one kind of a Lisp
-integer.  This simplifies many Lisp programs that use integers, and
-makes integer calculations always fast.  If you want larger values,
-use Lisp floats, as Emacs has done since day one.
+Emacs can no longer be built with support of native compilation of
+Lisp programs.  This means Emacs builds much faster, and the problems
+that came with native compilation: the need to have GCC and Binutils
+installed, the complications of managing your @file{eln-cache}
+directories---all of that is now future history.  The simplicity and
+elegance of the Emacs byte-compiled code is now restored in all of its
+pristine beauty.
 
 @item
-Emacs no longer supports HarfBuzz as the engine for shaping complex
-text.  As you move back in time, we will gradually shed off all traces
-of support for complex text shaping, and this is one step in that
-direction.
+Emacs no longer builds by default with Cairo, even if it's present.
+The warnings about not using HarfBuzz are also gone, in preparation
+for complete removal of HarfBuzz support in previous Emacs versions.
+Fancy text shaping and display is becoming less important as you move
+back in time.  The @code{ftx} font backend is again part of Emacs, for
+the same reasons.
 
 @item
-We have removed support for building with the Jansson library, and
-consequently the native support for JSON parsing is gone.  The
-importance of JSON decreases as we go back in time, so for now using
-the Lisp code for handling it should be good enough; in one of the
-past Emacs versions, we intend to remove even that, as useless bloat.
-
-The library for supporting JSONRPC applications was removed for the
-same reason.
+As Motif becomes more and more important with moving farther into the
+past, we've reinstated the code which supports Motif in Emacs.
 
 @item
-The ``portable dumper'' feature is gone.  We are once again using the
-field-proven ``unexec'' way of dumping Emacs.  With that, the hope for
-being able to re-dump your customized Emacs session is also gone: why
-would anyone want to record their random customization experiments on
-disk, and restore them the next time they start Emacs?  And true
-Emacsers don't restart their Emacs sessions anyway.
+Emacs once again supports versions 5.3 and older OpenBSD system, which
+will be needed as you move back in time.
 
 @item
-We dropped the support for @acronym{XDG}-style configuration
-directories and the @env{XDG_CONFIG_HOME} environment variable.
-There's once again only one place where Emacs looks for its init
-files: the @file{~/.emacs.d} directory, with the @file{~/.emacs} file
-as fallback.  We think this will go a long way towards preventing
-confusion among users who for some reason have @env{XDG_CONFIG_HOME}
-set, thus risking to have their init files randomly spread between two
-places.  In one of the past Emacs versions, we intend to further
-simplify this, removing the @file{~/.emacs.d} place and leaving only
-@file{~/.emacs}; stay tuned.
-
-For similar reasons, we've removed the ``early init'' file.  You can
-now again use all the tricks you want to initialize variables like
-@code{package-user-dir} and @code{package-load-list} just in time for
-the packages to load.
+We've dropped support for Secure Computing filter on GNU/Linux.  The
+past world is much more secure than the present, so the complexities
+related with this stuff, which can only be explained by severe
+paranoia, are no longer justified.
 
-@command{emacsclient} no longer supports @acronym{XDG}-style directory
-trees, either.
+@item
+Emacs reverted back to supporting Unicode 13.x, since the following
+versions of the standards are not yet published where you are going.
+The @samp{emoji} script and the support for displaying Emoji sequences
+were removed for the same reasons: no one will produce them in the
+past.
 
 @item
-TLS connections are back to their lenient security settings.  We
-decided that too tight security settings are an annoyance for users,
-and make little sense considering the world-wide tendency to have
-fewer and fewer network security problems as we move back in time
-(those issues will be completely gone when networks disappear in some
-distant past).
+Mode-specific commands and the @kbd{M-S-x} command that invokes them
+were removed.  As you move back in time, the command set in Emacs
+becomes smaller, so any such filtering of applicable commands just
+gets in the way.
 
 @item
-The @code{server-after-make-frame-hook} hook was deleted, in
-preparation for removing the entire daemon business in some past Emacs
-version.  You will be glad to learn that setting up the GUI
-customizations of your sessions is now once again as easy as it ever
-was, with just the @code{after-make-frame-functions} to use.
+We have removed the system for displaying documentation of groups of
+related functions, the @kbd{shortdoc-display-group} command to go with
+it, and the corresponding ``See also'' button in the @file{*Help*}
+buffer.  That should make searching for certain functions simpler:
+just use the venerable @samp{apropos} commands.
 
 @item
-The @code{flex} completion style was removed.  We feel that it
-unnecessarily complicates the Emacs user experience, and therefore
-will continue to remove other tricky completion styles, until in some
-past Emacs version we get to a single original style Emacs pioneered
-decades ago.  Long live simplicity; down with complications!
+The @code{context-menu-mode} was removed, and with it the context
+menus popped by pressing the right mouse button.  This is one small
+step towards freeing Emacs (and eventually, the whole world of
+computing) from the tyranny of the GUI pointing devices in general,
+and moving back to the simplicity of text-mode user interfaces.
+Down with mice and other rodents!
 
 @item
-The optional display of the fill-column indicator is no longer
-supported.  With the display sizes becoming smaller and smaller as you
-move back in time, we feel that the display itself will always show
-you where to fill or wrap your text, and do this much more easily and
-reliably than any such display indicator.
+The commands @kbd{C-x 4 4} and @kbd{C-x 5 5} for displaying the
+results in a new window/frame re gone.  We are quite certain that
+creating a new window/frame before running a command is much simpler,
+and doesn't require a complication of a new prefix.
 
 @item
-We removed the features that made visiting large files easier.  Thus,
-Emacs will no longer suggest visiting a large file literally, nor
-offer the @code{so-long} mode to deal with overly-long lines.  We
-decided that this simplification is worthwhile, given that the general
-tendency of having very large files is becoming a rarity as we move
-back in time.
+The behavior of active minibuffers when switching frames is now the
+perfect mess it should be: sometimes the minibuffer moves to the new
+selected frame, sometimes it doesn't, and sometimes you get an error.
+This makes Emacs usage much more fun, as you get to guess the result,
+instead of having it boringly consistent.
 
 @item
-We have removed the feature that displayed echo-area messages without
-hiding content of the active minibuffer.  This should prevent user
-confusion from having two unrelated pieces of text staring at them,
-with no clear separation between them.  Users with good memories (and
-Emacs users are all expected to be of that kind) will have no trouble
-keeping the minibuffer text in their minds, and typing the responses
-without actually seeing the prompts.
+Compact mode-line display mode has been removed.  The items displayed
+on the mode line are now always in the same place, and if there's not
+enough space for them, they are not displayed at all, instead of being
+confusingly displayed in a different position.  You no longer need to
+think twice where to find a particular mode-line element on display.
 
 @item
-Horizontal scrolling using the mouse or touchpad has been removed.  In
-the past, wide monitors will become less popular, so horizontal
-scrolling will no longer be needed.  Removal of the mouse support for
-horizontal scrolling is the first step towards its complete removal in
-prior Emacs versions.
+Many commands and options related to tab bars were removed, including
+(but not limited to) frame-specific appearance of tab bars, the
+@code{tab-bar-format} option, the @kbd{C-x t n}, @kbd{C-x t N},
+@kbd{C-x t M}, and @kbd{C-x t G} commands, and many mouse gestures on
+the tab bar.  We are going to delete the tab bar support from Emacs in
+one of the past versions, and this is a step in that direction.
 
 @item
-The @code{main-thread} variable and @code{list-threads} were removed,
-and @code{thread-join} no longer returns the result of the finished
-thread.  We intend to remove the support for Lisp threads in some past
-Emacs version, so we continue removing the associated complexities and
-features as we go back in time.
+The ``transient'' input methods have been removed; use @kbd{C-\} to
+turn input methods on and off instead.  This is in preparation for
+complete removal of input methods from Emacs in version 19, and
+consistent with the fact that the number of input methods we support
+becomes smaller as you move back in time.
 
 @item
-Tab bar and window tab-lines were removed.  This should make the Emacs
-display simpler and less cluttered, and help those users who disable
-menu bar and tool bar in their GUI sessions.  The fashion to provide
-tabs in every GUI application out there is gaining less and less
-popularity as we move back in time, and will completely disappear at
-some past point; removing the tabs from Emacs is the step in that
-direction.
+We disabled @code{show-paren-mode} by default, since we think the
+venerable @code{blink-matching-paren} feature is more than enough, and
+better fits the simplicity of past Emacs versions.  It will definitely
+be better when colors are removed from Emacs in the distant past.
+
+For the same reason, sub-groups in interactive regexp searches are no
+longer highlighted in distinct colors.
 
 @item
-Displaying line numbers for a buffer is only possibly using add-on
-features, such as @code{linum-mode}, which can only display the
-numbers in the display margins.  Line-number display using these
-features is also slow, as we firmly believe such a feature is
-un-Emacsy and should not have been included in Emacs to begin with.
-Consequently, @code{display-line-numbers-mode} was removed.
+On our permanent quest for simplifying Emacs, we've removed the Ispell
+command @code{ispell-comment-or-string-at-point}; the old-time friend
+@code{ispell-comments-and-strings} should suffice.
 
 @item
-On our permanent quest for simplifying Emacs, we've removed the
-support for changing the font size by turning the mouse wheel.
+Many Gnus commands and options were deemed to unnecessarily complicate
+the use of Gnus (which is too complex to begin with), and thus were
+removed.  This includes @code{gnus-topic-display-predicate},
+@code{gnus-process-mark-toggle}, @code{gnus-registry-register-all},
+@code{gnus-paging-select-next}, and many others.  The @code{nnselect}
+backend was deleted for the same reason.
 
 @item
-Several commands, deemed to be unnecessary complications, have been
-removed.  Examples include @code{make-empty-file},
-@code{font-lock-refontify}, @code{xref-find-definitions-at-mouse},
-@code{make-frame-on-monitor}, and @code{diff-buffers}.
+The @file{project.el} package have been redesigned to remove many
+unnecessary features, so that just the bare essentials remain.  We
+plan on removing this package from Emacs in a previous version, but
+decided to begin with removing some extra features first.
 
 @item
 To keep up with decreasing computer memory capacity and disk space, many
-other functions and files have been eliminated in Emacs 26.3.
+other functions and files have been eliminated in Emacs 27.2.
 @end itemize
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 2fafb43..83847fb 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -219,7 +219,7 @@ Appendices
 * GNU Free Documentation License:: The license for this documentation.
 * Emacs Invocation::    Hairy startup options.
 * X Resources::         X resources for customizing Emacs.
-* Antinews::            Information about Emacs version 26.
+* Antinews::            Information about Emacs version 27.
 * Mac OS / GNUstep::     Using Emacs under macOS and GNUstep.
 * Microsoft Windows::   Using Emacs on Microsoft Windows and MS-DOS.
 * Manifesto::           What's GNU?  Gnu's Not Unix!
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 06e2642..8cf7568 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -458,8 +458,8 @@ Create a new frame using the default frame parameters
 @item C-x 5 c
 @kindex C-x 5 c
 @findex clone-frame
-Create a new frame using the parameters of the current frame
-(@code{clone-frame}).
+Create a new frame using the window configuration and frame parameters
+of the current frame (@code{clone-frame}).
 
 @item C-x 5 b @var{bufname} @key{RET}
 Select buffer @var{bufname} in another frame.  This runs
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 7e8b0e5..d1380bc 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -945,7 +945,7 @@ the author's description of the changes in the revision on 
the current
 line.
 
 @item w
-Annotate the working revision--the one you are editing.  If you used
+Annotate the working revision---the one you are editing.  If you used
 @kbd{p} and @kbd{n} to browse to other revisions, use this key to
 return to your working revision.
 
diff --git a/doc/lispref/anti.texi b/doc/lispref/anti.texi
index ced8082..118df05 100644
--- a/doc/lispref/anti.texi
+++ b/doc/lispref/anti.texi
@@ -6,186 +6,179 @@
 @c This node must have no pointers.
 
 @node Antinews
-@appendix Emacs 26 Antinews
+@appendix Emacs 27 Antinews
 @c Update the elisp.texi Antinews menu entry with the above version number.
 
 For those users who live backwards in time, here is information about
-downgrading to Emacs version 26.3.  We hope you will enjoy the greater
+downgrading to Emacs version 27.2.  We hope you will enjoy the greater
 simplicity that results from the absence of many @w{Emacs
 @value{EMACSVER}} features.
 
 @itemize @bullet
 @item
-Lisp objects are again implemented on the C level as integer types,
-not as pointers.  This might be a small step for Emacs Lisp users, but
-it's a giant leap for the Emacs developers who work on the C level,
-since it is now again easy to print Lisp object in the debugger in the
-decimal format, which is so much easier for debugging.  It also makes
-calling Emacs functions from the debugger easier, and allows us to
-freely mix integers and Lisp objects in the C code.
+The annoying @code{lexical-binding} local variable now heeds the
+value of @code{enable-local-variables}: if it's @code{nil}, the
+@code{lexical-binding} cookie is ignored.  We are working hard on
+removing the lexical-binding support in some past Emacs version, and
+this small step advances us back to that change.
 
 @item
-The test suite was removed from the distribution tarball.  We believe
-that tests need seldom if ever be run, certainly not by the end
-users.  Removing the tests from the tarball makes it much smaller,
-which is important since disk space becomes more and more at premium
-as you move back in time.
+The @code{load-dangerous-libraries} variable is not obsolete, as it
+must be used to allow loading Lisp compiled by XEmacs, which will
+become more and more important as you move back in time.
 
 @item
-Dynamic module support is disabled by default.  This both makes Emacs
-smaller (a worthy goal by itself), and removes the complications and
-additional complexity related with installing module support files and
-letting random shared objects an opportunity to be loaded into Emacs
-and mess with it.
+The optional @var{modes} argument of @code{interactive} is not
+supported, and every command is deemed applicable to any major mode.
+We believe this makes the life of Lisp programmers much simpler, as
+there's now no need to tag commands with the modes where they make
+sense.
 
 @item
-You now must activate any installed packages only after loading your
-init files.  That requires an explicit call to
-@code{package-initialize} in your init file, which is a Good Thing, as
-it makes you think seriously where and indeed whether you'd like your
-packages to become available to your sessions.  Simplicity should
-tramp convenience!
+Shorthands for Lisp symbols have been removed, which makes loading
+Lisp files and handling Lisp symbols much simpler and more efficient.
+This is important for decent performance on slower CPUs as you move
+back in time.
 
 @item
 To reduce the amount of code in Emacs related to unimportant features,
-we've removed native rotation and resizing of images.  You will have
-to build Emacs with ImageMagick if you want to resize or rotate images
-inside Emacs.  We don't expect anyone to miss that.
+we've removed the variables @code{global-minor-modes} and
+@code{local-minor-modes}.  If your Lisp program needs to determine
+whether some minor mode is in effect, it will have to test explicitly
+for every mode.  We don't expect anyone to miss those fancy variables.
 
 @item
-We've re-enabled color fonts usage by the XFT font back-end.  We
-consider the availability of these fonts more important than a random
-crash here and there, especially since the use of these fonts for
-displaying Emoji will become less and less important as we travel back
-in time, and will completely disappear in some past Emacs version.
+The default preference for servicing sub-processes that produce output
+at a high rate, and the associated variable
+@code{process-prioritize-lower-fds}, have been removed.  Moving back
+in time means fewer and fewer programs can produce such high-rate
+output, so this features becomes just useless crud.
 
 @item
-The function @code{network-interface-list} can now return only IPv4
-addresses.  We consider the complexity introduced by IPv6 to be too
-much to be justified, and on the other hand its removal is the step in
-the right direction, given that IPv6 is expected to be completely
-removed as we move back in time.
+The encodings that are variants of EBCDIC were removed.  This includes
+@code{ibm256}, @code{ibm273}, and others---variants of the EBCDIC
+encoding tailored for some Japanese and European locales.  You won't
+need those where you are going.
 
 @item
-The limit on repetitions in regular expressions was reduced to
-@ifnottex
-2**15 @minus{} 1.
-@end ifnottex
-@tex
-@math{2^{15}-1}.
-@end tex
-We envision that regular expressions will become more and more simple
-as we move towards the distant past.
+The ``Bindat type expression'' description language has been removed,
+as the existing data layout specifications are perfectly suited for
+this job.
 
 @item
 To simplify code and reduce complexity, we removed the capability of
-searching programs on remote hosts in @code{executable-find}.  If you
-really need this feature (why would you?), you can always write your
-own shell script and run it on the remote.
+specifying the success handler in @code{condition-case} via the
+@code{:success} keyword.  If you really need this feature (why would
+you?), you can always write some simple Lisp that has the same effect.
 
 @item
-The @code{:extend} face attribute is no longer available; all faces
-have their background color extended by default past end of line.
-This should significantly simplify face management and remove
-unnecessary code bloat, as well as make faces significantly simpler to
-understand and use.
+Emacs modules can no longer provide interactive functions, or install
+finalizers, nor open channels to existing pipe sub-processes.  All
+this is extra ballast, especially since we plan on removing modules in
+some past Emacs version.  The @code{make_unibyte_string} module API
+was removed for the same reason.
 
 @item
-The predicates @code{display-blink-cursor-p} and
-@code{display-symbol-keys-p} were deleted.  They are rarely if ever
-needed, and can easily be substituted by appropriate calls to old and
-proven APIs like @code{display-graphic-p}.  As an additional bonus,
-writing Lisp programs that depend on this functionality will make sure
-the programmer understands better what exactly is the required
-features of the display terminal.
+To keep Emacs clean and elegant, we've removed the
+@code{print-integers-as-characters} option.  Recognizing characters by
+their decimal codes is a basic requirement for Emacs Lisp programmers,
+and with the expected decrease in use of Unicode characters, this will
+be soon limited to ASCII only: surely something you all can master!
 
 @item
-Relative directories in the value of the @env{HOME} environment
-variable are once again interpreted relative to the
-@code{default-directory} of the current buffer.  This is much simpler,
-and also allows @env{HOME} to resolve to a different place in
-different buffers, which allows some interesting applications.
+The optional @var{count} argument of the @code{directory-files}
+function has been removed.  Extracting the first @var{n} members from
+the full list is trivial, so this is a significant simplification for
+an insignificant cost.
 
-For the same reasons, @code{file-name-absolute-p} now again considers
-@file{~foo} an absolute file name, even if there's no known user
-@samp{foo}.  This means a Lisp program which uses such file names will
-always work the same on any system, regardless of its known users.
+@item
+Functions that create sub-processes and network connections no longer
+accept the @code{:coding} argument; use
+@code{set-process-coding-system} or bind
+@code{coding-system-for-read/write} instead: again, a significant
+reduction in Emacs complexity for little or no cost.
+
+@item
+We deleted from the macros @code{define-derived-mode} and
+@code{define-minor-mode} the code which allowed using the
+@code{:interactive} argument.  The possibility of marking a mode
+non-interactive makes very little sense,
+
+@item
+The possibility of having links to man pages in doc strings has been
+removed.  Use plain text instead, if you need such references.
+
+@item
+Temporary buffers are no longer exempt from running any buffer-related
+hooks.  Programs that don't want such hooks in some buffer can always
+disable it locally, whereas making that simpler complicates Emacs for
+no good reason.
 
 @item
-File-related primitives like @code{file-attributes},
-@code{file-modes}, @code{file-newer-than-file-p}, and some others once
-again return @code{nil} when the underlying low-level APIs fail,
-instead of signaling an error.  We decided that functions which signal
-errors require more complex code from Lisp programs which use them,
-and found this complexity unjustified when returning @code{nil} will
-do.
+Several features that complicated the byte compiler have been removed:
 
+@itemize @minus
 @item
-Similarly, old-style backquotes no longer signal errors; they generate
-warnings instead.  You can remove error handling from programs that
-use backquotes.
+The checks for missing declarations of dynamic variables.  This will
+continue making less and less sense as we move away of lexical-binding
+support.
 
 @item
-Formatting floating-point numbers has been sped up by letting the
-underlying implementation produce unpredictable values, instead of
-signaling errors when the number is too large to format correctly.  We
-believe the Emacs Lisp programmers should always know what they are
-doing when they deal with floating-point values.
+The ability of compiling symlinked @file{*.el} files, which is really
+gross: copy the files instead.
 
 @item
-The function @code{read-char-from-minibuffer} was deleted.  We decided
-that @code{read-char} should be enough for any Lisp program that needs
-to ask the user for a single-character input, in recognition of the
-fact that nothing makes Emacs Lisp hackers rejoice more than the need
-to sit down and write yet another interactive question-and-answer
-function, and make it optimal for each specific case.  Consequently,
-no history is provided for such responses (why would someone want
-history of single-key strokes, anyway?).
+The warnings about too-wide doc strings---that is just a nuisance, as
+the programmers should be trusted to know what they are doing.
+@end itemize
+
+
+@item
+We deleted several features of the @code{pcase} macro, in accordance
+with our general plane to remove @code{pcase} from Emacs:
 
+@itemize @minus
 @item
-The function @code{ngettext} was deleted.  Non-English languages will
-become less and less widespread, let alone useful, as you move back in
-time, so we took this small step in that direction, and simplified
-Emacs as a nice bonus.
+The @code{cl-type} pattern.
 
 @item
-Focus-change notifications on text-mode frames are no longer
-recognized or supported.  You can now safely disregard the possibility
-of receiving such notifications on TTY frames.  This is one small step
-on the long road of removing all non-character input events Emacs
-supports on TTY frames.
+the @code{pcase-setq} macro.
+
+@item
+The @code{pcase-compile-patterns} function.
+@end itemize
 
 @item
-Face specifications in @code{face-remapping-alist} now have to be
-buffer-specific, without any differences between windows showing the
-same buffers.  This allowed us to remove a lot of unneeded code bloat
-from Emacs, and make the face handling much simpler.
+Some of the keywords used in Edebug specification lists were deemed to
+be of little use, and were therefore removed: @code{&interpose},
+@code{&error}, and @code{&name}.  The long-term plane is for Emacs to
+drop Edebug entirely, leaving only the trusted Lisp debugger, and we
+continue working according to that plan.
 
 @item
-The @samp{%o} and @samp{%x} formats now always produce unsigned
-values, as you'd expect.  This allows you to reveal the underlying
-machine representation, which is different on each architecture,
-something we consider a valuable feature.
+The function @code{object-intervals} was dropped, as a Lisp program
+can easily collect the intervals of a buffer or a string by iterating
+through them one by one.
 
 @item
-We no longer highlight in @code{font-lock-warning-face} symbols with
-confusable quote characters, such as U+2018.  Detecting them
-needed  non-trivial amount of code, and we firmly believe that Lisp
-programmers always know what they are doing, and don't need to be
-annoyed with typefaces that stand out and distract.
+We decided that the @code{require-theme} function is an unnecessary
+complication, so we deleted it.  Lisp programs can easily search along
+@code{custom-theme-load-path} instead.
 
 @item
-The function @code{file-system-info} was dropped on Posix platforms,
-since you can always invoke @command{df} instead and parse its
-output.
+The convenience functions @code{length<}, @code{length>}, and
+@code{length=} were removed, as using @code{length} followed by a
+comparison should be good enough for everyone, especially considering
+that the typical length of a list keeps going down as you move back
+through time.
 
 @item
-The functions that implement the @samp{base64url} encoding were
-removed, as they can always be emulated by suitable tweaking of the
-normal base-64 encoding.  No need to bloat Emacs and force Lisp
-programmers learn more interfaces on this account.
+The variable @code{current-minibuffer-command} is no longer available,
+as we found little justification for keeping it.
 
 @item
 As part of the ongoing quest for simplicity, many other functions and
-variables have been eliminated.
+variables have been eliminated.  Other functions and variables, that
+were declared obsolete since Emacs 23, have been added back, in
+preparation for releasing Emacs 23 in some distant past.
 @end itemize
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index e9e306f..da3a3a8 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -234,7 +234,7 @@ To view this manual in other formats, click
 
 Appendices
 
-* Antinews::                Info for users downgrading to Emacs 26.
+* Antinews::                Info for users downgrading to Emacs 27.
 * GNU Free Documentation License:: The license for this documentation.
 * GPL::                     Conditions for copying and changing GNU Emacs.
 * Tips::                    Advice and coding conventions for Emacs Lisp.
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index d27cfb8..f5a4240 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -1986,7 +1986,7 @@ feature for matching regular expressions from end to 
beginning.  It's
 not worth the trouble of implementing that.
 @end deffn
 
-@defun string-match regexp string &optional start
+@defun string-match regexp string &optional start inhibit-modify
 This function returns the index of the start of the first match for
 the regular expression @var{regexp} in @var{string}, or @code{nil} if
 there is no match.  If @var{start} is non-@code{nil}, the search starts
@@ -2011,8 +2011,10 @@ For example,
 The index of the first character of the
 string is 0, the index of the second character is 1, and so on.
 
-If this function finds a match, the index of the first character beyond
-the match is available as @code{(match-end 0)}.  @xref{Match Data}.
+By default, if this function finds a match, the index of the first
+character beyond the match is available as @code{(match-end 0)}.
+@xref{Match Data}.  If @var{inhibit-modify} is non-@code{nil}, the
+match data isn't modified.
 
 @example
 @group
@@ -2033,16 +2035,18 @@ This predicate function does what @code{string-match} 
does, but it
 avoids modifying the match data.
 @end defun
 
-@defun looking-at regexp
+@defun looking-at regexp &optional inhibit-modify
 This function determines whether the text in the current buffer directly
 following point matches the regular expression @var{regexp}.  ``Directly
 following'' means precisely that: the search is ``anchored'' and it can
 succeed only starting with the first character following point.  The
 result is @code{t} if so, @code{nil} otherwise.
 
-This function does not move point, but it does update the match data.
-@xref{Match Data}.  If you need to test for a match without modifying
-the match data, use @code{looking-at-p}, described below.
+This function does not move point, but it does update the match data
+(if @var{inhibit-modify} is @code{nil} or missing, which is the
+default).  @xref{Match Data}.  As a convenience, instead of using the
+@var{inhibit-modify} argument, you can use @code{looking-at-p},
+described below.
 
 In this example, point is located directly before the @samp{T}.  If it
 were anywhere else, the result would be @code{nil}.
@@ -2149,13 +2153,13 @@ backtracking specified by the POSIX standard for 
regular expression
 matching.
 @end deffn
 
-@defun posix-looking-at regexp
+@defun posix-looking-at regexp &optional inhibit-modify
 This is like @code{looking-at} except that it performs the full
 backtracking specified by the POSIX standard for regular expression
 matching.
 @end defun
 
-@defun posix-string-match regexp string &optional start
+@defun posix-string-match regexp string &optional start inhibit-modify
 This is like @code{string-match} except that it performs the full
 backtracking specified by the POSIX standard for regular expression
 matching.
diff --git a/doc/misc/ert.texi b/doc/misc/ert.texi
index 770a5b7..440c61a 100644
--- a/doc/misc/ert.texi
+++ b/doc/misc/ert.texi
@@ -415,7 +415,7 @@ emacs -batch -l ert -l my-tests.el \
 @end example
 
 By default, ERT test failure summaries are quite brief in batch
-mode--only the names of the failed tests are listed.  If the
+mode---only the names of the failed tests are listed.  If the
 EMACS_TEST_VERBOSE environment variable is set, the failure summaries
 will also include the data from the failing test.
 
diff --git a/doc/misc/mairix-el.texi b/doc/misc/mairix-el.texi
index d0ec552..e57b5ed 100644
--- a/doc/misc/mairix-el.texi
+++ b/doc/misc/mairix-el.texi
@@ -60,6 +60,8 @@ database.
 * Using::                       List of interactive functions
 * Extending::                   Support your favorite mail reader!
 * GNU Free Documentation License::  The license for this documentation.
+* Function Index:               Function Index.
+* Variable Index:               Variable Index.
 @end menu
 
 @node About
@@ -339,4 +341,14 @@ And that's it!
 @appendix GNU Free Documentation License
 @include doclicense.texi
 
+@node Function Index
+@unnumbered Function Index
+
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+
+@printindex vr
+
 @bye
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 8c9306b..5a2f30a 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -3,8 +3,166 @@ ERC NEWS                                                      
 -*- outline -*-
 Copyright (C) 2006-2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
-* For changes after ERC 5.3, see the main Emacs NEWS file
+Please send ERC bug reports to 'bug-gnu-emacs@gnu.org',
+and Cc the 'emacs-erc@gnu.org' mailing list as well.
+If possible, use 'M-x erc-bug' or 'M-x report-emacs-bug'.
 
+This file is about changes in ERC, the powerful, modular, and
+extensible IRC (Internet Relay Chat) client distributed with
+GNU Emacs since Emacs version 22.1.
+
+
+* Changes in ERC 5.4
+
+** Starting with Emacs 28.1 and ERC 5.4, ERC NEWS are added here again.
+After ERC 5.3, since November 2012, ERC's NEWS items were added in the
+main Emacs NEWS file, and users were referred to there.  Now, starting
+with Emacs 28.1 and ERC 5.4, which mark ERC's release to GNU ELPA, ERC
+NEWS have been moved to this file again, so that we can include a NEWS
+file consisting only of ERC changes in ERC's package on GNU ELPA.
+
+The NEWS entries for ERC changes in Emacs 28.1 have been moved from
+the main Emacs NEWS file to here.  For ERC NEWS entries corresponding
+to Emacs versions before 28, to avoid modifying the NEWS file for all
+of those releases, the ERC NEWS entries have only been copied below,
+and the NEWS.* files were left intact.
+
+*** New option 'erc-rename-buffers'.
+
+*** 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.
+
+*** The display of irc commands in the current buffer has been disabled.
+
+*** 'erc-version' now follows the Emacs version.
+
+*** ERC can now hide message types by network or channel.
+'erc-hide-list' will hide all messages of the specified type, while
+'erc-network-hide-list' and 'erc-channel-hide-list' will only hide the
+specified message types for the respective specified targets.
+
+*** Reconnection is now asynchronous.
+
+*** Nick completion is now case-insensitive again after inadvertently
+being made case-sensitive in Emacs 24.2.
+
+*** New variable 'erc-default-port-tls' used to connect to TLS IRC
+servers.
+
+*** New hook 'erc-insert-done-hook'.
+This hook is called after strings have been inserted into the buffer,
+and is free to alter point and window configurations, as it's not
+called from inside a 'save-excursion', as opposed to 'erc-insert-post-hook'.
+
+*** 'erc-button-google-url' has been renamed to 'erc-button-search-url'
+and its value has been changed to Duck Duck Go.
+
+*** 'erc-send-pre-hook' and 'erc-send-this' have been obsoleted.
+The user option to use instead to alter text to be sent is now
+'erc-pre-send-functions'.
+
+*** Improve matching/highlighting of nicknames.
+Open and close parenthesis and apostrophe are not considered valid
+nick characters anymore, matching the given grammar in RFC 2812
+section 2.3.1.  This enables correct matching and highlighting of
+nicks when they are surrounded by parentheses, like "(nick)", and when
+adjacent to an apostrophe, like "nick's".
+
+*** Set 'erc-button-url-regexp' to 'browse-url-button-regexp'
+which better handles surrounding pair of parentheses.
+
+*** New function 'erc-switch-to-buffer-other-window'
+which is like 'erc-switch-to-buffer', but opens the buffer in another
+window.
+
+*** New function 'erc-track-switch-buffer-other-window'
+which is like 'erc-track-switch-buffer', but opens the buffer in
+another window.
+
+*** NickServ passwords can now be retrieved from auth-source.
+The 'erc-use-auth-source-for-nickserv-password' user option enables
+querying auth-source for NickServ passwords.  To enable this, add the
+following to your init file:
+
+    (setq erc-use-auth-source-for-nickserv-password t)
+
+*** NickServ identification now prompts for password last.
+When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
+be unconditionally prompted interactively for a password, regardless
+of the value of 'erc-nickserv-passwords', which was effectively
+ignored (same for the new
+'erc-use-auth-source-for-nickserv-password').  This limitation is now
+lifted, and the user is interactively prompted last, after the other
+identification methods have run.
+
+*** The '/ignore' command will now ask for a timeout to stop ignoring the user.
+Allowed inputs are seconds or ISO8601-like periods like "1h" or "4h30m".
+
+*** ERC now recognizes 'C-]' for italic text.
+Italic text is displayed in the new 'erc-italic-face'.
+
+*** erc-match.el now supports 'message' highlight type (not including the 
nick).
+The 'erc-current-nick-highlight-type', 'erc-pal-highlight-type',
+'erc-fool-highlight-type', 'erc-keyword-highlight-type', and
+'erc-dangerous-host-highlight-type' user options now support a
+'message' type for highlighting the entire message but not the
+sender's nick.
+
+*** erc-status-sidebar.el is now part of ERC.
+The 'erc-status-sidebar' package which provides a HexChat-like
+activity overview sidebar for joined IRC channels is now part of ERC.
+
+*** erc-tls now supports specifying a TLS client certificate.
+The 'erc-tls' function has been updated to allow specifying a TLS
+client certificate for authentication, as an alternative to NickServ
+password-based authentication.  This is referred to as "CertFP" (short
+for Certificate Fingerprint) by several IRC networks.  See the Info
+node "(erc) Connecting" in the ERC manual for more details and
+examples on how to specify and use TLS client certificates with
+'erc-tls'.
+
+*** Update IRC-related references to point to Libera.Chat.
+The Free Software Foundation and the GNU Project have moved their
+official IRC channels from the Freenode network to Libera.Chat.
+For the original announcement and the follow-up update, including
+more details, see:
+
+https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00005.html
+https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00007.html
+
+Given the relocation of GNU and FSF's official IRC channels, as well
+as #emacs and various other Emacs-themed channels (see the link below)
+to Libera.Chat, IRC-related references in the Emacs repository have
+now been updated to point to Libera.Chat.
+
+https://lists.gnu.org/archive/html/info-gnu-emacs/2021-06/msg00000.html
+
+*** Add 'erc-track-select-mode-line-face' (obsoletes 'erc-track-find-face').
+The 'erc-track-find-face' function of the erc-track module has been
+declared obsolete and rewritten as 'erc-track-select-mode-line-face',
+with different expected arguments (the current and old faces are now
+separated) and clearer documentation.
+
+*** Add '/opme' and '/deopme' convenience commands.
+The new '/opme' convenience command asks ChanServ to set the operator
+status for the current nick in the current channel, and '/deopme'
+unsets it.
+
+*** Add '/wii' convenience command for whois with idle time.
+The new '/wii' convenience command calls the '/whois' command with the
+given nick as both arguments, which is useful for displaying the whois
+information for the nick along with idle time, even if the nick is on
+a different server than the one the current user is connected to.
+Using the given nick itself instead of the server it is connected to
+is not standardized, but is widely supported across IRC networks.
+
+*** Add 'erc-bug' command for reporting ERC bugs.
+The new 'erc-bug' command prompts for a subject, and passes it on to
+'report-emacs-bug' along with the current ERC version, and adds the
+ERC mailing list in Cc.
+
+
 * Changes in ERC 5.3
 
 ** New function `erc-tls' is to be used for connecting to a server via TLS.
@@ -249,6 +407,7 @@ message types are "333" and "353", respectively.
 **** Turn this into the "xdcc" module for ERC, so that it can be more
 easily enabled.
 
+
 * Changes in ERC 5.2
 
 ** M-x erc RET now starts ERC.
@@ -528,6 +687,7 @@ not.
 **** New function: `erc-toggle-timestamps'.
 Toggles display of timestamps.
 
+
 * Changes in ERC 5.1.4
 
 ** Make find-function and find-variable work in Emacs 22 for
@@ -551,6 +711,7 @@ is deactivated.
 **** Fix some errors that occur when exiting Emacs without first
 quitting open IRC servers.
 
+
 * Changes in ERC 5.1.3
 
 ** Fix use of /quote command with no initial whitespace.
@@ -665,6 +826,7 @@ modules.
 
 **** Don't complete the user's current nickname.
 
+
 * Changes in ERC 5.1.2
 
 ** Fix compiler errors in erc-autojoin.el and erc-dcc.el.
@@ -701,6 +863,7 @@ A side effect of using this new method is that there will 
only be one
 space before a right timestamp in any saved logs.  If this is
 unacceptable, set `erc-timestamp-use-align-to' to nil.
 
+
 * Changes in ERC 5.1.1
 
 ** Fix a requirement on cl.el.
@@ -734,6 +897,7 @@ new `erc-timestamp-right-align-by-pixel' option to non-nil.
 **** Since most of these changes are now merged into Emacs22, detect
 whether we need these changes and install them only if necessary.
 
+
 * Changes in ERC 5.1
 
 ** Improve XEmacs compatibility.
@@ -940,10 +1104,12 @@ the right margin.
 
 **** Helps ERC work correctly in viper-mode.
 
+
 * Changes in ERC 5.0.4
 
 ** Fix a problem with undo in channels.
 
+
 * Changes in ERC 5.0.3
 
 ** Fix typo in the `ctcp-request-to' entry of the English catalog.
@@ -985,6 +1151,7 @@ indicator.  Previously, there was an additional 
unnecessary space.
 **** Fix an error that occurred when unchecked buffers existed when
 invoking /QUIT.
 
+
 * Changes in ERC 5.0.2
 
 ** If a channel key is required for a certain channel, ERC will prompt
@@ -1018,6 +1185,7 @@ choice anymore.
 
 **** You can now save logs and truncate buffers from the menu-bar.
 
+
 * Changes in ERC 5.0.1
 
 ** Narrowing in ERC buffers no longer causes formatting errors.
@@ -1032,6 +1200,7 @@ choice anymore.
 This means that `erc-track-priority-faces-only', `erc-track-exclude',
 and `erc-track-exclude-types' now work with server buffers.
 
+
 * Changes in ERC 5.0
 
 ** Channel members are now stored as a hash-table.
@@ -1276,6 +1445,7 @@ in XEmacs.
     mode-line where modified channels are shown (only works in GNU
     Emacs versions above 21.3).
 
+
 * Changes in ERC 4.0
 
 ** The module system has again changed a lot.  You can now customize
@@ -1299,6 +1469,7 @@ in XEmacs.
   openprojects to freenode.  You may need to update your configuration
   for a successful automatic nickserv identification.
 
+
 * Changes in ERC 3.0.cvs.20030119
 
 ** New module erc-dcc:
@@ -1330,6 +1501,7 @@ Same applies to timestamps.  You no longer need to 
(require
 the rest should be automatic.
 
 
+----------------------------------------------------------------------
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
@@ -1344,3 +1516,10 @@ 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/>.
+
+
+Local variables:
+coding: utf-8
+mode: outline
+paragraph-separate: "[         ]*$"
+end:
diff --git a/etc/NEWS b/etc/NEWS
index 7b218aa..b91a5cb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -118,6 +118,15 @@ Emacs buffers, like indentation and the like.  The new ert 
function
 * Incompatible Lisp Changes in Emacs 29.1
 
 ---
+** The 'inhibit-changing-match-data' variable is now obsolete.
+Instead, functions like 'string-match' and 'looking-at' now take an
+optional 'inhibit-modify' argument.
+
+---
+** 'gnus-define-keys' is now obsolete.
+Use 'define-keymap' instead.
+
+---
 ** MozRepl has been removed from js.el.
 MozRepl was removed from Firefox in 2017, so this code doesn't work
 with recent versions of Firefox.
diff --git a/etc/NEWS.28 b/etc/NEWS.28
index 8808413..09537d7 100644
--- a/etc/NEWS.28
+++ b/etc/NEWS.28
@@ -352,8 +352,8 @@ of the next command to be displayed in a new frame.
 
 +++
 *** New command 'clone-frame' (bound to 'C-x 5 c').
-This is like 'C-x 5 2', but uses the frame parameters of the current
-frame instead of 'default-frame-alist'.
+This is like 'C-x 5 2', but uses the window configuration and frame
+parameters of the current frame instead of 'default-frame-alist'.
 
 ---
 *** Default values of 'frame-title-format' and 'icon-title-format' have 
changed.
@@ -912,6 +912,109 @@ now been updated to point to Libera.Chat.
 https://lists.gnu.org/archive/html/info-gnu-emacs/2021-06/msg00000.html
 
 
+* Incompatible Editing Changes in Emacs 28.1
+
+---
+** 'toggle-truncate-lines' now disables 'visual-line-mode'.
+This is for symmetry with 'visual-line-mode', which disables
+'truncate-lines'.
+
+---
+** 'electric-indent-mode' now also indents inside strings and comments.
+(This only happens when indentation function also supports this.)
+
+To recover the previous behavior you can use:
+
+    (add-hook 'electric-indent-functions
+              (lambda (_) (if (nth 8 (syntax-ppss)) 'no-indent)))
+
+---
+** The 'M-o' ('facemenu-keymap') global binding has been removed.
+To restore the old binding, say something like:
+
+    (require 'facemenu)
+    (define-key global-map "\M-o" 'facemenu-keymap)
+    (define-key facemenu-keymap "\es" 'center-line)
+    (define-key facemenu-keymap "\eS" 'center-paragraph)
+
+The last two lines are not strictly necessary if you don't care about
+having those two commands on the 'M-o' keymap; see the next section.
+
+---
+** The 'M-o M-s' and 'M-o M-S' global bindings have been removed.
+Use 'M-x center-line' and 'M-x center-paragraph' instead.  See the
+previous section for how to get back the old bindings.  Alternatively,
+if you only want these two commands to have global bindings they had
+before, you can add the following to your init file:
+
+    (define-key global-map "\M-o\M-s" 'center-line)
+    (define-key global-map "\M-o\M-S" 'center-paragraph)
+
+---
+** The 'M-o M-o' global binding has been removed.
+Use 'M-x font-lock-fontify-block' instead, or the new 'C-x x f'
+command, which updates the syntax highlighting in the current buffer.
+
+---
+** The escape sequence '\e[29~' in Xterm is now mapped to 'menu'.
+Xterm sends this sequence for both 'F16' and 'Menu' keys
+It used to be mapped to 'print' but we couldn't find a terminal
+that uses this sequence for any kind of 'Print' key.
+This makes the Menu key (see https://en.wikipedia.org/wiki/Menu_key)
+work for 'context-menu-mode' in Xterm.
+
+---
+** New user option 'xterm-store-paste-on-kill-ring'.
+If non-nil (the default), Emacs pushes pasted text onto the kill ring
+(if using an xterm-like terminal that supports bracketed paste).
+Setting this to nil inhibits that.
+
+---
+** 'vc-print-branch-log' shows the change log from its root directory.
+It previously used to use the default directory.
+
+---
+** 'project-shell' and 'shell' now use 'pop-to-buffer-same-window'.
+This is to keep the same behavior as Eshell.
+
+---
+** In 'nroff-mode', 'center-line' is no longer bound to a key.
+The original key binding was 'M-s', which interfered with I-search,
+since the latter uses 'M-s' as a prefix key of the search prefix map.
+
+---
+** In 'f90-mode', the backslash character ('\') no longer escapes.
+For about a decade, the backslash character has no longer had a
+special escape syntax in Fortran F90.  To get the old behavior back,
+say something like:
+
+    (modify-syntax-entry ?\\ "\\" f90-mode-syntax-table)
+
++++
+** Setting 'fill-column' to nil is obsolete.
+This undocumented use of 'fill-column' is now obsolete.  To disable
+auto filling, turn off 'auto-fill-mode' instead.
+
+For instance, you could add something like the following to your init
+file:
+
+    (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
+
+** Xref migrated from EIEIO to cl-defstruct for its core objects.
+This means that 'oref' and 'with-slots' no longer works on them, and
+'make-instance' can no longer be used to create those instances (which
+wasn't recommended anyway).  Packages should keep to using the
+functions like 'xref-make', 'xref-make-match', 'xref-make-*-location',
+as well as accessor functions 'xref-item-summary' and
+'xref-item-location'.
+
+Among the benefits are better performance (noticeable when there are a
+lot of matches) and improved flexibility: 'xref-match-item' instances
+do not require that 'location' inherits from 'xref-location' anymore
+(that class was removed), so packages can create new location types to
+use with "match items" without adding EIEIO as a dependency.
+
+
 * Editing Changes in Emacs 28.1
 
 ** Input methods
@@ -1090,7 +1193,7 @@ buffer to be able to move point to the inaccessible 
portion.
 'goto-line-relative' is bound to 'C-x n g'.
 
 +++
-** 'got-char' prompts for the character position.
+** 'goto-char' prompts for the character position.
 When called interactively, 'goto-char' now offers the position at
 point as the default.
 
@@ -2852,76 +2955,8 @@ non-nil.
 
 ** ERC
 
----
-*** NickServ passwords can now be retrieved from auth-source.
-The 'erc-use-auth-source-for-nickserv-password' user option enables
-querying auth-source for NickServ passwords.  To enable this, add the
-following to your init file:
-
-    (setq erc-use-auth-source-for-nickserv-password t)
-
----
-*** NickServ identification now prompts for password last.
-When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
-be unconditionally prompted interactively for a password, regardless
-of the value of 'erc-nickserv-passwords', which was effectively
-ignored (same for the new
-'erc-use-auth-source-for-nickserv-password').  This limitation is now
-lifted, and the user is interactively prompted last, after the other
-identification methods have run.
-
----
-*** The '/ignore' command will now ask for a timeout to stop ignoring the user.
-Allowed inputs are seconds or ISO8601-like periods like "1h" or "4h30m".
-
----
-*** ERC now recognizes 'C-]' for italic text.
-Italic text is displayed in the new 'erc-italic-face'.
-
----
-*** erc-match.el now supports 'message' highlight type (not including the 
nick).
-The 'erc-current-nick-highlight-type', 'erc-pal-highlight-type',
-'erc-fool-highlight-type', 'erc-keyword-highlight-type', and
-'erc-dangerous-host-highlight-type' user options now support a
-'message' type for highlighting the entire message but not the
-sender's nick.
-
----
-*** erc-status-sidebar.el is now part of ERC.
-The 'erc-status-sidebar' package which provides a HexChat-like
-activity overview sidebar for joined IRC channels is now part of ERC.
-
-+++
-*** erc-tls now supports specifying a TLS client certificate.
-The 'erc-tls' function has been updated to allow specifying a TLS
-client certificate for authentication, as an alternative to NickServ
-password-based authentication.  This is referred to as "CertFP" (short
-for Certificate Fingerprint) by several IRC networks.  See the Info
-node "(erc) Connecting" in the ERC manual for more details and
-examples on how to specify and use TLS client certificates with
-'erc-tls'.
-
----
-*** Add 'erc-track-select-mode-line-face' (obsoletes 'erc-track-find-face').
-The 'erc-track-find-face' function of the erc-track module has been
-declared obsolete and rewritten as 'erc-track-select-mode-line-face',
-with different expected arguments (the current and old faces are now
-separated) and clearer documentation.
-
----
-*** Add '/opme' and '/deopme' convenience commands.
-The new '/opme' convenience command asks ChanServ to set the operator
-status for the current nick in the current channel, and '/deopme'
-unsets it.
-
----
-*** Add '/wii' convenience command for whois with idle time.
-The new '/wii' convenience command calls the '/whois' command with the
-given nick as both arguments, which is useful for displaying the whois
-information for the nick along with idle time, even if the nick is on
-a different server than the one the current user is connected to.
-Using the given nick itself instead of the server it is connected to
-is not standardized, but is widely supported across IRC networks.
+*** Starting with Emacs 28.1 and ERC 5.4, see the ERC-NEWS file for
+user-visible changes in ERC.
 
 ** xwidget-webkit mode
 
@@ -3238,109 +3273,6 @@ This new 'etc-authors-mode' provides font-locking for 
displaying the
 "etc/AUTHORS" file from the Emacs distribution, and not much else.
 
 
-* Incompatible Editing Changes in Emacs 28.1
-
----
-** 'toggle-truncate-lines' now disables 'visual-line-mode'.
-This is for symmetry with 'visual-line-mode', which disables
-'truncate-lines'.
-
----
-** 'electric-indent-mode' now also indents inside strings and comments.
-(This only happens when indentation function also supports this.)
-
-To recover the previous behavior you can use:
-
-    (add-hook 'electric-indent-functions
-              (lambda (_) (if (nth 8 (syntax-ppss)) 'no-indent)))
-
----
-** The 'M-o' ('facemenu-keymap') global binding has been removed.
-To restore the old binding, say something like:
-
-    (require 'facemenu)
-    (define-key global-map "\M-o" 'facemenu-keymap)
-    (define-key facemenu-keymap "\es" 'center-line)
-    (define-key facemenu-keymap "\eS" 'center-paragraph)
-
-The last two lines are not strictly necessary if you don't care about
-having those two commands on the 'M-o' keymap; see the next section.
-
----
-** The 'M-o M-s' and 'M-o M-S' global bindings have been removed.
-Use 'M-x center-line' and 'M-x center-paragraph' instead.  See the
-previous section for how to get back the old bindings.  Alternatively,
-if you only want these two commands to have global bindings they had
-before, you can add the following to your init file:
-
-  (define-key global-map "\M-o\M-s" 'center-line)
-  (define-key global-map "\M-o\M-S" 'center-paragraph)
-
----
-** The 'M-o M-o' global binding has been removed.
-Use 'M-x font-lock-fontify-block' instead, or the new 'C-x x f'
-command, which updates the syntax highlighting in the current buffer.
-
----
-** The escape sequence '\e[29~' in Xterm is now mapped to 'menu'.
-Xterm sends this sequence for both 'F16' and 'Menu' keys
-It used to be mapped to 'print' but we couldn't find a terminal
-that uses this sequence for any kind of 'Print' key.
-This makes the Menu key (see https://en.wikipedia.org/wiki/Menu_key)
-work for 'context-menu-mode' in Xterm.
-
----
-** New user option 'xterm-store-paste-on-kill-ring'.
-If non-nil (the default), Emacs pushes pasted text onto the kill ring
-(if using an xterm-like terminal that supports bracketed paste).
-Setting this to nil inhibits that.
-
----
-** 'vc-print-branch-log' shows the change log from its root directory.
-It previously used to use the default directory.
-
----
-** 'project-shell' and 'shell' now use 'pop-to-buffer-same-window'.
-This is to keep the same behavior as Eshell.
-
----
-** In 'nroff-mode', 'center-line' is no longer bound to a key.
-The original key binding was 'M-s', which interfered with I-search,
-since the latter uses 'M-s' as a prefix key of the search prefix map.
-
----
-** In 'f90-mode', the backslash character ('\') no longer escapes.
-For about a decade, the backslash character has no longer had a
-special escape syntax in Fortran F90.  To get the old behavior back,
-say something like:
-
-    (modify-syntax-entry ?\\ "\\" f90-mode-syntax-table)
-
-+++
-** Setting 'fill-column' to nil is obsolete.
-This undocumented use of 'fill-column' is now obsolete.  To disable
-auto filling, turn off 'auto-fill-mode' instead.
-
-For instance, you could add something like the following to your init
-file:
-
-    (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
-
-** Xref migrated from EIEIO to cl-defstruct for its core objects.
-This means that 'oref' and 'with-slots' no longer works on them, and
-'make-instance' can no longer be used to create those instances (which
-wasn't recommended anyway).  Packages should keep to using the
-functions like 'xref-make', 'xref-make-match', 'xref-make-*-location',
-as well as accessor functions 'xref-item-summary' and
-'xref-item-location'.
-
-Among the benefits are better performance (noticeable when there are a
-lot of matches) and improved flexibility: 'xref-match-item' instances
-do not require that 'location' inherits from 'xref-location' anymore
-(that class was removed), so packages can create new location types to
-use with "match items" without adding EIEIO as a dependency.
-
-
 * Incompatible Lisp Changes in Emacs 28.1
 
 +++
diff --git a/etc/TODO b/etc/TODO
index ffc5ef3..cd06b1e 100644
--- a/etc/TODO
+++ b/etc/TODO
@@ -444,6 +444,25 @@ consistency checks that make sure the new code computes 
the same results
 as the old code.  And once that works well, we can remove the old code
 and old fields.
 
+** Implement Unicode-compliant display of "default-ignorable" characters
+See the "Characters Ignored for Display" section of paragraph 5.21 in
+the Unicode Standard for the details.
+
+The implementation would import the data from Unicode UCD file
+DerivedCoreProperties.txt, and provide a minor mode that arranges for
+the characters with the Default_Ignorable_Code_Point (DI) property to
+be hidden on display.  One way of implementing that could be via
+glyphless-char-display-control; that one is global, but maybe there's
+a way of making it buffer-local.  Alternatively, this could be
+implemented in C in the display engine.
+
+An additional aspect of this is the display of U+00AD SOFT HYPHEN as
+invisible except at line boundaries.  Note that this would need to
+support hard (physical) newlines in the buffer as well as soft
+wrapping of long lines under 'visual-line-mode'.  The algorithm for
+selecting the wrap point may also need be changed to break at the soft
+hyphen.
+
 ** FFI (foreign function interface)
 See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html
 
diff --git a/lisp/bindings.el b/lisp/bindings.el
index 1cd2216..e397e44 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -505,7 +505,7 @@ mouse-1: Display Line and Column Mode Menu"))
      local-map ,mode-line-column-line-number-mode-map
      mouse-face mode-line-highlight
      ;; XXX needs better description
-     help-echo "Size indication mode\n\
+     help-echo "Buffer Position
 mouse-1: Display Line and Column Mode Menu")
     (size-indication-mode
      (8 ,(propertize
diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el
index 9f3d515..59be3f4 100644
--- a/lisp/emulation/viper-cmd.el
+++ b/lisp/emulation/viper-cmd.el
@@ -35,9 +35,7 @@
 (defvar viper--key-maps)
 (defvar viper--intercept-key-maps)
 (defvar iso-accents-mode)
-(defvar quail-mode)
 (defvar quail-current-str)
-(defvar mark-even-if-inactive)
 (defvar viper--init-message)
 (defvar viper-initial)
 (defvar undo-beg-posn)
@@ -69,8 +67,7 @@
         (nm-p (intern (concat snm "-p")))
         (nms (intern (concat snm "s"))))
     `(defun ,nm-p (com)
-       (consp (viper-memq-char com ,nms)
-             ))))
+       (consp (memq com ,nms)))))
 
 ;; Variables for defining VI commands
 
@@ -1035,23 +1032,23 @@ as a Meta key and any number of multiple escapes are 
allowed."
        cmd-info
        cmd-to-exec-at-end)
     (while (and cont
-               (viper-memq-char char
-                                (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
-                                      viper-buffer-search-char)))
+                (memq char
+                      (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
+                            viper-buffer-search-char)))
       (if com
          ;; this means that we already have a command character, so we
          ;; construct a com list and exit while.  however, if char is "
          ;; it is an error.
          (progn
            ;; new com is (CHAR . OLDCOM)
-           (if (viper-memq-char char '(?# ?\")) (user-error viper-ViperBell))
+            (if (memq char '(?# ?\")) (user-error viper-ViperBell))
            (setq com (cons char com))
            (setq cont nil))
        ;; If com is nil we set com as char, and read more.  Again, if char is
        ;; ", we read the name of register and store it in viper-use-register.
        ;; if char is !, =, or #, a complete com is formed so we exit the while
        ;; loop.
-       (cond ((viper-memq-char char '(?! ?=))
+        (cond ((memq char '(?! ?=))
               (setq com char)
               (setq char (read-char))
               (setq cont nil))
@@ -1091,7 +1088,7 @@ as a Meta key and any number of multiple escapes are 
allowed."
                 `(key-binding (char-to-string ,char)))))
 
       ;; as com is non-nil, this means that we have a command to execute
-      (if (viper-memq-char (car com) '(?r ?R))
+      (if (memq (car com) '(?r ?R))
          ;; execute appropriate region command.
          (let ((char (car com)) (com (cdr com)))
            (setq prefix-arg (cons value com))
@@ -2603,12 +2600,12 @@ On reaching beginning of line, stop and signal error."
   (let ((prev-char (viper-char-at-pos 'backward))
        (saved-point (point)))
     ;; skip non-newline separators backward
-    (while (and (not (viper-memq-char prev-char '(nil \n)))
+    (while (and (not (memq prev-char '(nil \n)))
                (< lim (point))
                ;; must be non-newline separator
                (if (eq viper-syntax-preference 'strict-vi)
-                   (viper-memq-char prev-char '(?\  ?\t))
-                 (viper-memq-char (char-syntax prev-char) '(?\  ?-))))
+                    (memq prev-char '(?\  ?\t))
+                  (memq (char-syntax prev-char) '(?\  ?-))))
       (viper-backward-char-carefully)
       (setq prev-char (viper-char-at-pos 'backward)))
 
@@ -2622,12 +2619,12 @@ On reaching beginning of line, stop and signal error."
 
     ;; skip again, but make sure we don't overshoot the limit
     (if twice
-       (while (and (not (viper-memq-char prev-char '(nil \n)))
+        (while (and (not (memq prev-char '(nil \n)))
                    (< lim (point))
                    ;; must be non-newline separator
                    (if (eq viper-syntax-preference 'strict-vi)
-                       (viper-memq-char prev-char '(?\  ?\t))
-                     (viper-memq-char (char-syntax prev-char) '(?\  ?-))))
+                        (memq prev-char '(?\  ?\t))
+                      (memq (char-syntax prev-char) '(?\  ?-))))
          (viper-backward-char-carefully)
          (setq prev-char (viper-char-at-pos 'backward))))
 
@@ -2645,10 +2642,10 @@ On reaching beginning of line, stop and signal error."
     (viper-forward-word-kernel val)
     (if com
        (progn
-         (cond ((viper-char-equal com ?c)
+          (cond ((eq com ?c)
                 (viper-separator-skipback-special 'twice viper-com-point))
                ;; Yank words including the whitespace, but not newline
-               ((viper-char-equal com ?y)
+                ((eq com ?y)
                 (viper-separator-skipback-special nil viper-com-point))
                ((viper-dotable-command-p com)
                 (viper-separator-skipback-special nil viper-com-point)))
@@ -2666,10 +2663,10 @@ On reaching beginning of line, stop and signal error."
                (viper-skip-nonseparators 'forward)
                (viper-skip-separators t))
     (if com (progn
-             (cond ((viper-char-equal com ?c)
+              (cond ((eq com ?c)
                     (viper-separator-skipback-special 'twice viper-com-point))
                    ;; Yank words including the whitespace, but not newline
-                   ((viper-char-equal com ?y)
+                    ((eq com ?y)
                     (viper-separator-skipback-special nil viper-com-point))
                    ((viper-dotable-command-p com)
                     (viper-separator-skipback-special nil viper-com-point)))
@@ -4714,15 +4711,15 @@ Please, specify your level now: "))
 (defun viper-submit-report ()
   "Submit bug report on Viper."
   (interactive)
-  (defvar viper-color-display-p)
+  (defvar x-display-color-p)
   (defvar viper-frame-parameters)
   (defvar viper-minibuffer-emacs-face)
   (defvar viper-minibuffer-vi-face)
   (defvar viper-minibuffer-insert-face)
   (let ((reporter-prompt-for-summary-p t)
-       (viper-color-display-p (if (viper-window-display-p)
-                             (viper-color-display-p)
-                              'non-x))
+        (x-display-color-p (if (viper-window-display-p)
+                              (x-display-color-p)
+                             'non-x))
         (viper-frame-parameters (frame-parameters (selected-frame)))
        (viper-minibuffer-emacs-face (if (viper-has-face-support-p)
                                          (facep
@@ -4780,7 +4777,7 @@ Please, specify your level now: "))
                        'viper-expert-level
                        'major-mode
                        'window-system
-                       'viper-color-display-p
+                        'x-display-color-p
                        'viper-frame-parameters
                        'viper-minibuffer-vi-face
                        'viper-minibuffer-insert-face
diff --git a/lisp/emulation/viper-ex.el b/lisp/emulation/viper-ex.el
index ef15779..85c8b87 100644
--- a/lisp/emulation/viper-ex.el
+++ b/lisp/emulation/viper-ex.el
@@ -25,7 +25,6 @@
 ;;; Code:
 
 ;; Compiler pacifier
-(defvar read-file-name-map)
 (defvar viper-use-register)
 (defvar viper-s-string)
 (defvar viper-shift-width)
diff --git a/lisp/emulation/viper-init.el b/lisp/emulation/viper-init.el
index fe37048..e3790b7 100644
--- a/lisp/emulation/viper-init.el
+++ b/lisp/emulation/viper-init.el
@@ -25,16 +25,12 @@
 ;;; Code:
 
 ;; compiler pacifier
-(defvar mark-even-if-inactive)
-(defvar quail-mode)
 (defvar iso-accents-mode)
 (defvar viper-current-state)
 (defvar viper-version)
 (defvar viper-expert-level)
 (defvar current-input-method)
 (defvar default-input-method)
-(defvar describe-current-input-method-function)
-(defvar bar-cursor)
 (defvar cursor-type)
 ;; end pacifier
 
@@ -48,11 +44,6 @@
 
 (define-obsolete-function-alias 'viper-device-type #'window-system "27.1")
 
-(defun viper-color-display-p ()
-  (condition-case nil
-      (display-color-p)
-    (error nil)))
-
 ;; in XEmacs: device-type is tty on tty and stream in batch.
 (defun viper-window-display-p ()
   (and window-system (not (memq window-system '(tty stream pc)))))
@@ -81,7 +72,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)
-       ((viper-color-display-p))
+        ((x-display-color-p))
        (t (memq window-system '(pc)))))
 
 
diff --git a/lisp/emulation/viper-mous.el b/lisp/emulation/viper-mous.el
index 02db39f..3d55690 100644
--- a/lisp/emulation/viper-mous.el
+++ b/lisp/emulation/viper-mous.el
@@ -26,7 +26,6 @@
 
 ;; compiler pacifier
 (defvar double-click-time)
-(defvar mouse-track-multi-click-time)
 (defvar viper-search-start-marker)
 (defvar viper-local-search-start-marker)
 (defvar viper-search-history)
@@ -76,8 +75,8 @@ or a triple-click."
 
 ;; remembers prefix argument to pass along to commands invoked by second
 ;; click.
-;; This is needed because in Emacs (not XEmacs), assigning to prefix-arg
-;; causes Emacs to count the second click as if it was a single click
+;; This is needed because assigning to prefix-arg causes Emacs to
+;; count the second click as if it was a single click
 (defvar viper-global-prefix-argument nil)
 
 
diff --git a/lisp/emulation/viper-util.el b/lisp/emulation/viper-util.el
index 0f6dceb..71043b1 100644
--- a/lisp/emulation/viper-util.el
+++ b/lisp/emulation/viper-util.el
@@ -29,9 +29,6 @@
 
 ;; Compiler pacifier
 (defvar viper-minibuffer-current-face)
-(defvar viper-minibuffer-insert-face)
-(defvar viper-minibuffer-vi-face)
-(defvar viper-minibuffer-emacs-face)
 (defvar viper-replace-overlay-face)
 (defvar viper-fast-keyseq-timeout)
 (defvar ex-unix-type-shell)
@@ -64,22 +61,8 @@
 (define-obsolete-function-alias 'viper-iconify
   #'iconify-or-deiconify-frame "27.1")
 
-
-;; CHAR is supposed to be a char or an integer (positive or negative)
-;; LIST is a list of chars, nil, and negative numbers
-;; Check if CHAR is a member by trying to convert in characters, if necessary.
-;; Introduced for compatibility with XEmacs, where integers are not the same as
-;; chars.
-(defun viper-memq-char (char list)
-  (cond ((and (integerp char) (>= char 0))
-        (memq char list))
-       ((memq char list))))
-
-;; Check if char-or-int and char are the same as characters
-(defun viper-char-equal (char-or-int char)
-  (cond ((and (integerp char-or-int) (>= char-or-int 0))
-        (= char-or-int char))
-       ((eq char-or-int char))))
+(define-obsolete-function-alias 'viper-memq-char #'memq "29.1")
+(define-obsolete-function-alias 'viper-char-equal #'eq "29.1")
 
 ;; Like =, but accommodates null and also is t for eq-objects
 (defun viper= (char char1)
@@ -88,8 +71,7 @@
         (= char char1))
        (t nil)))
 
-(defsubst viper-color-display-p ()
-  (x-display-color-p))
+(define-obsolete-function-alias 'viper-color-display-p #'x-display-color-p 
"29.1")
 
 (defun viper-get-cursor-color (&optional _frame)
   (cdr (assoc 'cursor-color (frame-parameters))))
@@ -110,7 +92,7 @@ Otherwise return the normal value."
 
 ;; cursor colors
 (defun viper-change-cursor-color (new-color &optional frame)
-  (if (and (viper-window-display-p) (viper-color-display-p)
+  (if (and (viper-window-display-p) (x-display-color-p)
           (stringp new-color) (x-color-defined-p new-color)
           (not (string= new-color (viper-get-cursor-color))))
       (modify-frame-parameters
@@ -142,7 +124,7 @@ 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) (viper-color-display-p))
+  (if (and (viper-window-display-p) (x-display-color-p))
       (let ((color (viper-get-cursor-color)))
        (if (and (stringp color) (x-color-defined-p color)
                 ;; there is something fishy in that the color is not saved if
@@ -1183,25 +1165,23 @@ This option is appropriate if you like Emacs-style 
words."
            (looking-at (concat "[" viper-strict-ALPHA-chars addl-chars "]"))
          (or
           ;; or one of the additional chars being asked to include
-          (viper-memq-char char (viper-string-to-list addl-chars))
+           (memq char (viper-string-to-list addl-chars))
           (and
            ;; not one of the excluded word chars (note:
            ;; viper-non-word-characters is a list)
-           (not (viper-memq-char char viper-non-word-characters))
+            (not (memq char viper-non-word-characters))
            ;; char of the Viper-word syntax class
-           (viper-memq-char (char-syntax char)
-                            (viper-string-to-list viper-ALPHA-char-class))))))
-    ))
+            (memq (char-syntax char)
+                  (viper-string-to-list viper-ALPHA-char-class))))))))
 
 (defun viper-looking-at-separator ()
   (let ((char (char-after (point))))
     (if char
        (if (eq viper-syntax-preference 'strict-vi)
-           (viper-memq-char char (viper-string-to-list viper-strict-SEP-chars))
+            (memq char (viper-string-to-list viper-strict-SEP-chars))
          (or (eq char ?\n) ; RET is always a separator in Vi
-             (viper-memq-char (char-syntax char)
-                              (viper-string-to-list viper-SEP-char-class)))))
-    ))
+              (memq (char-syntax char)
+                               (viper-string-to-list 
viper-SEP-char-class)))))))
 
 (defsubst viper-looking-at-alphasep (&optional addl-chars)
   (or (viper-looking-at-separator) (viper-looking-at-alpha addl-chars)))
@@ -1327,8 +1307,7 @@ This option is appropriate if you like Emacs-style words."
                    ;; of the excluded characters
                    (if (and (eq syntax-of-char-looked-at ?w)
                             (not negated-syntax))
-                       (not (viper-memq-char
-                             char-looked-at viper-non-word-characters))
+                        (not (memq char-looked-at viper-non-word-characters))
                      t))
                   (funcall skip-syntax-func 1)
                 0)
diff --git a/lisp/emulation/viper.el b/lisp/emulation/viper.el
index e9c0fb5..1ee5365 100644
--- a/lisp/emulation/viper.el
+++ b/lisp/emulation/viper.el
@@ -304,7 +304,6 @@
 
 ;; compiler pacifier
 (defvar mark-even-if-inactive)
-(defvar quail-mode)
 (defvar viper-expert-level)
 (defvar viper-mode-string)
 (defvar viper-major-mode-modifier-list)
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index 17d5b61..2c1d700 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -389,12 +389,11 @@ REGEXP is the regular expression which matched for this 
button."
     (mouse-set-point event)
     (erc-button-press-button)))
 
-;; XEmacs calls this via widget-button-press with a bunch of arguments
-;; which we don't care about.
 (defun erc-button-press-button (&rest _ignore)
   "Check text at point for a callback function.
 If the text at point has a `erc-callback' property,
 call it with the value of the `erc-data' text property."
+  (declare (advertised-calling-convention () "29.1"))
   (interactive)
   (let* ((data (get-text-property (point) 'erc-data))
          (fun (get-text-property (point) 'erc-callback)))
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 308812f..4a86fa7 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -58,7 +58,7 @@
 
 ;;; Code:
 
-(load "erc-loaddefs" nil t)
+(load "erc-loaddefs" 'noerror 'nomessage)
 
 (require 'cl-lib)
 (require 'format-spec)
@@ -69,6 +69,9 @@
 (require 'iso8601)
 (eval-when-compile (require 'subr-x))
 
+(defconst erc-version "5.3"
+  "This version of ERC.")
+
 (defvar erc-official-location
   "https://www.gnu.org/software/emacs/erc.html (mailing list: 
emacs-erc@gnu.org)"
   "Location of the ERC client on the Internet.")
@@ -2385,6 +2388,7 @@ If ARG is non-nil, show the *erc-protocol* buffer."
         (let ((inhibit-read-only t)
               (msg (list
                     (concat "Version: " erc-debug-irc-protocol-version)
+                    (concat "ERC-Version: " erc-version)
                     (concat "Emacs-Version: " emacs-version)
                     (erc-make-notice
                      (concat "This buffer displays all IRC protocol "
@@ -3613,7 +3617,7 @@ If USER is omitted, close the current query buffer if one 
exists
 
 (defun erc-quit/part-reason-default ()
   "Default quit/part message."
-  (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version))
+  (erc-version nil 'bold-erc))
 
 
 (defun erc-quit-reason-normal (&optional s)
@@ -3766,7 +3770,8 @@ the message given by REASON."
 
 (defun erc-cmd-SV ()
   "Say the current ERC and Emacs version into channel."
-  (erc-send-message (format "I'm using ERC with GNU Emacs %s (%s%s)%s."
+  (erc-send-message (format "I'm using ERC %s with GNU Emacs %s (%s%s)%s."
+                            erc-version
                             emacs-version
                             system-configuration
                             (concat
@@ -4845,8 +4850,8 @@ See also `erc-display-message'."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice
      nick (format
-           "VERSION \C-bERC\C-b - an IRC client for Emacs %s (\C-b%s\C-b)"
-           emacs-version
+           "VERSION %s (\C-b%s\C-b)"
+           (erc-version nil 'bold-erc)
            erc-official-location)))
   nil)
 
@@ -6616,6 +6621,15 @@ If BUFFER is nil, update the mode line in all ERC 
buffers."
 
 ;; Miscellaneous
 
+(defun erc-bug (subject)
+  "Send a bug report to the Emacs bug tracker and ERC mailing list."
+  (interactive "sBug Subject: ")
+  (report-emacs-bug
+   (format "ERC %s: %s" erc-version subject))
+  (save-excursion
+    (goto-char (point-min))
+    (insert "X-Debbugs-CC: emacs-erc@gnu.org\n")))
+
 (defun erc-port-to-string (p)
   "Convert port P to a string.
 P may be an integer or a service name."
@@ -6632,12 +6646,18 @@ P may be an integer or a service name."
           s
         n))))
 
-(defun erc-version (&optional here)
+(defun erc-version (&optional here bold-erc)
   "Show the version number of ERC in the minibuffer.
-If optional argument HERE is non-nil, insert version number at point."
+If optional argument HERE is non-nil, insert version number at point.
+If optional argument BOLD-ERC is non-nil, display \"ERC\" as bold."
   (interactive "P")
   (let ((version-string
-         (format "ERC (IRC client for Emacs %s)" emacs-version)))
+         (format "%s %s (IRC client for GNU Emacs %s)"
+                 (if bold-erc
+                     "\C-bERC\C-b"
+                   "ERC")
+                 erc-version
+                 emacs-version)))
     (if here
         (insert version-string)
       (if (called-interactively-p 'interactive)
diff --git a/lisp/frame.el b/lisp/frame.el
index e97b990..2c73737 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -786,25 +786,26 @@ When called from Lisp, returns the new frame."
       (make-frame)
     (select-frame (make-frame))))
 
-(defun clone-frame (&optional frame use-default-parameters)
-  "Make a new frame with the same parameters as FRAME.
-With a prefix arg (USE-DEFAULT-PARAMETERS), use
-`default-frame-alist' instead.
+(defun clone-frame (&optional frame no-windows)
+  "Make a new frame with the same parameters and windows as FRAME.
+With a prefix arg NO-WINDOWS, don't clone the window configuration.
 
 FRAME defaults to the selected frame.  The frame is created on the
 same terminal as FRAME.  If the terminal is a text-only terminal then
 also select the new frame."
-  (interactive "i\nP")
-  (if use-default-parameters
-      (make-frame-command)
-    (let* ((default-frame-alist (seq-filter
-                                 (lambda (elem)
-                                   (not (eq (car elem) 'name)))
-                                 (frame-parameters frame)))
-           (new-frame (make-frame)))
-      (unless (display-graphic-p)
-        (select-frame new-frame))
-      new-frame)))
+  (interactive (list (selected-frame) current-prefix-arg))
+  (let* ((frame (or frame (selected-frame)))
+         (windows (unless no-windows
+                    (window-state-get (frame-root-window frame))))
+         (default-frame-alist
+           (seq-remove (lambda (elem) (eq (car elem) 'name))
+                       (frame-parameters frame)))
+         (new-frame (make-frame)))
+    (when windows
+      (window-state-put windows (frame-root-window new-frame) 'safe))
+    (unless (display-graphic-p)
+      (select-frame new-frame))
+    new-frame))
 
 (defvar before-make-frame-hook nil
   "Functions to run before `make-frame' creates a new frame.")
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index 0163aba..a777157 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -305,7 +305,7 @@ Symbols are also allowed; their print names are used 
instead."
 
 (defmacro gnus-define-keys (keymap &rest plist)
   "Define all keys in PLIST in KEYMAP."
-  (declare (indent 1))
+  (declare (obsolete define-keymap "29.1") (indent 1))
   `(gnus-define-keys-1 ,(if (symbolp keymap) keymap `',keymap) (quote ,plist)))
 
 (defmacro gnus-define-keys-safe (keymap &rest plist)
@@ -319,6 +319,7 @@ Symbols are also allowed; their print names are used 
instead."
   `(gnus-define-keys-1 ,keymap (quote ,plist)))
 
 (defun gnus-define-keys-1 (keymap plist &optional safe)
+  (declare (obsolete define-keymap "29.1"))
   (when (null keymap)
     (error "Can't set keys in a null keymap"))
   (cond ((symbolp keymap) (error "First arg should be a keymap object"))
diff --git a/lisp/info-look.el b/lisp/info-look.el
index 309f2e8..4812035 100644
--- a/lisp/info-look.el
+++ b/lisp/info-look.el
@@ -358,9 +358,19 @@ If optional argument QUERY is non-nil, query for the help 
mode."
        (error "No %s help available for `%s'" topic mode))
     (setq info-lookup-mode mode)))
 
+(defun info-lookup--item-to-mode (item mode)
+  (let ((spec (cons mode (car (split-string (if (stringp item)
+                                                item
+                                              (symbol-name item))
+                                            "-")))))
+    (if (assoc spec (cdr (assq 'symbol info-lookup-alist)))
+        spec
+      mode)))
+
 (defun info-lookup (topic item mode)
   "Display the documentation of a help item."
   (or mode (setq mode (info-lookup-select-mode)))
+  (setq mode (info-lookup--item-to-mode item mode))
   (if-let ((info (info-lookup->mode-value topic mode)))
       (info-lookup--expand-info info)
     (error "No %s help available for `%s'" topic mode))
@@ -971,6 +981,67 @@ Return nil if there is nothing appropriate in the buffer 
near point."
              ("(cl)Function Index"    nil "^ -+ .*: " "\\( \\|$\\)")
              ("(cl)Variable Index"    nil "^ -+ .*: " "\\( \\|$\\)")))
 
+(mapc
+ (lambda (elem)
+   (let* ((prefix (car elem)))
+     (info-lookup-add-help
+      :mode (cons 'emacs-lisp-mode prefix)
+      :regexp (concat "\\b" prefix "-[^][()`'‘’,\" \t\n]+")
+      :doc-spec (cl-loop for node in (cdr elem)
+                         collect
+                         (list (if (string-match-p "^(" node)
+                                   node
+                                 (format "(%s)%s" prefix node))
+                               nil "^ -+ .*: " "\\( \\|$\\)")))))
+ ;; Below we have a list of prefixes (used to match on symbols in
+ ;; `emacs-lisp-mode') and the nodes where the function/variable
+ ;; indices live.  If the prefix is different than the name of the
+ ;; manual, then the full "(manual)Node" name has to be used.
+ '(("auth" "Function Index" "Variable Index")
+   ("autotype" "Command Index" "Variable Index")
+   ("calc" "Lisp Function Index" "Variable Index")
+   ;;("cc-mode" "Variable Index" "Command and Function Index")
+   ("dbus" "Index")
+   ("ediff" "Index")
+   ("eieio" "Function Index")
+   ("gnutls" "(emacs-gnutls)Variable Index" "(emacs-gnutls)Function Index")
+   ("mm" "(emacs-mime)Index")
+   ("epa" "Variable Index" "Function Index")
+   ("ert" "Index")
+   ("eshell" "Function and Variable Index")
+   ("eudc" "Index")
+   ("eww" "Variable Index" "Lisp Function Index")
+   ("flymake" "Index")
+   ("forms" "Index")
+   ("gnus" "Index")
+   ("htmlfontify" "Functions" "Variables & Customization")
+   ("idlwave" "Index")
+   ("ido" "Variable Index" "Function Index")
+   ("info" "Index")
+   ("mairix" "(mairix-el)Variable Index" "(mairix-el)Function Index")
+   ("message" "Index")
+   ("mh" "(mh-e)Option Index" "(mh-e)Command Index")
+   ("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")
+   ("sc" "Variable Index")
+   ("semantic" "Index")
+   ("ses" "Index")
+   ("sieve" "Index")
+   ("smtpmail" "Function and Variable Index")
+   ("srecode" "Index")
+   ("tramp" "Variable Index" "Function Index")
+   ("url" "Variable Index" "Function Index")
+   ("vhdl" "(vhdl-mode)Variable Index" "(vhdl-mode)Command Index")
+   ("viper" "Variable Index" "Function Index")
+   ("widget" "Index")
+   ("wisent" "Index")
+   ("woman" "Variable Index" "Command Index")))
+
 ;; docstrings talk about elisp, so have apropos-mode follow emacs-lisp-mode
 (info-lookup-maybe-add-help
  :mode 'apropos-mode
diff --git a/lisp/international/characters.el b/lisp/international/characters.el
index 475a669..5aefda2 100644
--- a/lisp/international/characters.el
+++ b/lisp/international/characters.el
@@ -116,11 +116,11 @@ Base characters (Unicode General Category L,N,P,S,Zs)")
 Combining diacritic or mark (Unicode General Category M)")
 
 ;; bidi types
-(define-category ?R "Right-to-left (strong)
+(define-category ?R "Strong R2L
 Characters with \"strong\" right-to-left directionality, i.e.
 with R, AL, RLE, or RLO Unicode bidi character type.")
 
-(define-category ?L "Left-to-right (strong)
+(define-category ?L "Strong L2R
 Characters with \"strong\" left-to-right directionality, i.e.
 with L, LRE, or LRO Unicode bidi character type.")
 
diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 8e81f79..82153ff 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -283,6 +283,7 @@ are also supported; unsupported long options are silently 
ignored."
       (funcall orig-fun
               file switches wildcard full-directory-p)
     ;; We need the directory in order to find the right handler.
+    (setq switches (or switches ""))
     (let ((handler (find-file-name-handler (expand-file-name file)
                                           'insert-directory))
          (orig-file file)
diff --git a/lisp/mh-e/mh-acros.el b/lisp/mh-e/mh-acros.el
index 8fdcf3c..6a03424 100644
--- a/lisp/mh-e/mh-acros.el
+++ b/lisp/mh-e/mh-acros.el
@@ -53,7 +53,7 @@
 ;;;###mh-autoload
 (defmacro mh-do-in-xemacs (&rest body)
   "Execute BODY if in XEmacs."
-  (declare (debug t) (indent defun))
+  (declare (obsolete nil "29.1") (debug t) (indent defun))
   (when (featurep 'xemacs) `(progn ,@body)))
 
 ;;;###mh-autoload
@@ -99,20 +99,18 @@ Otherwise, create macro NAME with ARG-LIST and BODY."
   "Make HOOK local if needed.
 XEmacs and versions of GNU Emacs before 21.1 require
 `make-local-hook' to be called."
+  (declare (obsolete nil "29.1"))
   (when (and (fboundp 'make-local-hook)
              (not (get 'make-local-hook 'byte-obsolete-info)))
     `(make-local-hook ,hook)))
 
 ;;;###mh-autoload
 (defmacro mh-mark-active-p (check-transient-mark-mode-flag)
-  "A macro that expands into appropriate code in XEmacs and nil in GNU Emacs.
-In GNU Emacs if CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then
-check if variable `transient-mark-mode' is active."
-  (cond ((featurep 'xemacs)             ;XEmacs
-         '(and (boundp 'zmacs-regions) zmacs-regions (region-active-p)))
-        ((not check-transient-mark-mode-flag) ;GNU Emacs
+  "If CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then check if
+variable `transient-mark-mode' is active."
+  (cond ((not check-transient-mark-mode-flag)
          '(and (boundp 'mark-active) mark-active))
-        (t                              ;GNU Emacs
+        (t
          '(and (boundp 'transient-mark-mode) transient-mark-mode
                (boundp 'mark-active) mark-active))))
 
@@ -164,12 +162,8 @@ preserved."
         (original-position (make-symbol "original-position"))
         (modified-flag (make-symbol "modified-flag")))
     `(save-excursion
-       (let* ((,event-window
-               (or (mh-funcall-if-exists posn-window (event-start ,event))
-                   (mh-funcall-if-exists event-window ,event)))
-              (,event-position
-               (or (mh-funcall-if-exists posn-point (event-start ,event))
-                   (mh-funcall-if-exists event-closest-point ,event)))
+       (let* ((,event-window (posn-window (event-start ,event)))
+              (,event-position (posn-point (event-start ,event)))
               (,original-window (selected-window))
               (,original-position (progn
                                    (set-buffer (window-buffer ,event-window))
diff --git a/lisp/mh-e/mh-alias.el b/lisp/mh-e/mh-alias.el
index 37fdb16..5761df5 100644
--- a/lisp/mh-e/mh-alias.el
+++ b/lisp/mh-e/mh-alias.el
@@ -112,10 +112,10 @@ COMMA-SEPARATOR is non-nil."
         (setq res (match-string 1 res)))
     ;; Replace "&" with capitalized username
     (if (string-search "&" res)
-        (setq res (mh-replace-regexp-in-string "&" (capitalize username) res)))
+        (setq res (replace-regexp-in-string "&" (capitalize username) res)))
     ;; Remove " character
     (if (string-search "\"" res)
-        (setq res (mh-replace-regexp-in-string "\"" "" res)))
+        (setq res (replace-regexp-in-string "\"" "" res)))
     ;; If empty string, use username instead
     (if (string-equal "" res)
         (setq res username))
@@ -155,7 +155,7 @@ Exclude all aliases already in `mh-alias-alist' from 
\"ali\""
                     (if (string-equal username realname)
                         (concat "<" username ">")
                       (concat realname " <" username ">"))))
-              (when (not (mh-assoc-string alias-name mh-alias-alist t))
+              (when (not (assoc-string alias-name mh-alias-alist t))
                 (setq passwd-alist (cons (list alias-name alias-translation)
                                          passwd-alist)))))))
         (forward-line 1)))
@@ -184,12 +184,12 @@ been loaded."
       (cond
        ((looking-at "^[ \t]"))          ;Continuation line
        ((looking-at "\\(.+\\): .+: .*$") ; A new -blind- MH alias
-        (when (not (mh-assoc-string (match-string 1) mh-alias-blind-alist t))
+        (when (not (assoc-string (match-string 1) mh-alias-blind-alist t))
           (setq mh-alias-blind-alist
                 (cons (list (match-string 1)) mh-alias-blind-alist))
           (setq mh-alias-alist (cons (list (match-string 1)) mh-alias-alist))))
        ((looking-at "\\(.+\\): .*$")    ; A new MH alias
-        (when (not (mh-assoc-string (match-string 1) mh-alias-alist t))
+        (when (not (assoc-string (match-string 1) mh-alias-alist t))
           (setq mh-alias-alist
                 (cons (list (match-string 1)) mh-alias-alist)))))
       (forward-line 1)))
@@ -200,7 +200,7 @@ been loaded."
           user)
       (while local-users
         (setq user (car local-users))
-        (if (not (mh-assoc-string (car user) mh-alias-alist t))
+        (if (not (assoc-string (car user) mh-alias-alist t))
             (setq mh-alias-alist (append mh-alias-alist (list user))))
         (setq local-users (cdr local-users)))))
   (run-hooks 'mh-alias-reloaded-hook)
@@ -239,16 +239,16 @@ done here."
   "Return expansion for ALIAS.
 Blind aliases or users from /etc/passwd are not expanded."
   (cond
-   ((mh-assoc-string alias mh-alias-blind-alist t)
+   ((assoc-string alias mh-alias-blind-alist t)
     alias)                              ; Don't expand a blind alias
-   ((mh-assoc-string alias mh-alias-passwd-alist t)
-    (cadr (mh-assoc-string alias mh-alias-passwd-alist t)))
+   ((assoc-string alias mh-alias-passwd-alist t)
+    (cadr (assoc-string alias mh-alias-passwd-alist t)))
    (t
     (mh-alias-ali alias))))
 
 (eval-and-compile
-  (mh-require 'crm nil t)                 ; completing-read-multiple
-  (mh-require 'multi-prompt nil t))
+  (require 'crm nil t)                 ; completing-read-multiple
+  (require 'multi-prompt nil t))
 
 ;;;###mh-autoload
 (defun mh-read-address (prompt)
@@ -281,7 +281,7 @@ Blind aliases or users from /etc/passwd are not expanded."
       (let* ((case-fold-search t)
              (beg (mh-beginning-of-word))
              (the-name (buffer-substring-no-properties beg (point))))
-        (if (mh-assoc-string the-name mh-alias-alist t)
+        (if (assoc-string the-name mh-alias-alist t)
             (message "%s -> %s" the-name (mh-alias-expand the-name))
           ;; Check if it was a single word likely to be an alias
           (if (and (equal mh-alias-flash-on-comma 1)
@@ -313,7 +313,7 @@ Blind aliases or users from /etc/passwd are not expanded."
                         res)
                   res)))
              ((t) (all-completions string mh-alias-alist pred))
-             ((lambda) (mh-test-completion string mh-alias-alist pred)))))))))
+             ((lambda) (test-completion string mh-alias-alist pred)))))))))
 
 
 ;;; Alias File Updating
diff --git a/lisp/mh-e/mh-comp.el b/lisp/mh-e/mh-comp.el
index 404b6b3..8d5a472 100644
--- a/lisp/mh-e/mh-comp.el
+++ b/lisp/mh-e/mh-comp.el
@@ -596,7 +596,7 @@ See also `mh-compose-forward-as-mime-flag',
         (set (make-local-variable 'mh-mail-header-separator)
              (save-excursion
                (goto-char (mh-mail-header-end))
-               (buffer-substring-no-properties (point) 
(mh-line-end-position))))
+               (buffer-substring-no-properties (point) (line-end-position))))
         (set (make-local-variable 'mail-header-separator) 
mh-mail-header-separator) ;override sendmail.el
         ;; If using MML, translate MH-style directive
         (if (equal mh-compose-insertion 'mml)
@@ -1077,7 +1077,6 @@ letter."
   ;; Insert identity.
   (mh-insert-identity mh-identity-default t)
   (mh-identity-make-menu)
-  (mh-identity-add-menu)
 
   ;; Cleanup possibly RFC2047 encoded subject header
   (mh-decode-message-subject)
@@ -1096,7 +1095,6 @@ letter."
   (setq mh-previous-window-config config)
   (setq mode-line-buffer-identification (list "    {%b}"))
   (mh-logo-display)
-  (mh-make-local-hook 'kill-buffer-hook)
   (add-hook 'kill-buffer-hook #'mh-tidy-draft-buffer nil t)
   (run-hook-with-args 'mh-compose-letter-function to subject cc))
 
@@ -1107,18 +1105,8 @@ The versions of MH-E, Emacs, and MH are shown."
   ;; Lazily initialize mh-x-mailer-string.
   (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
     (setq mh-x-mailer-string
-          (format "MH-E %s; %s; %sEmacs %s"
-                  mh-version mh-variant-in-use
-                  (if (featurep 'xemacs) "X" "GNU ")
-                  (cond ((not (featurep 'xemacs))
-                         (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
-                                       emacs-version)
-                         (match-string 0 emacs-version))
-                        ((string-match "[0-9.]*\\( +([ a-z]+[0-9]+)\\)?"
-                                       emacs-version)
-                         (match-string 0 emacs-version))
-                        (t (format "%s.%s" emacs-major-version
-                                   emacs-minor-version))))))
+          (format "MH-E %s; %s; Emacs %s"
+                  mh-version mh-variant-in-use emacs-version)))
   ;; Insert X-Mailer, but only if it doesn't already exist.
   (save-excursion
     (when (and mh-insert-x-mailer-flag
@@ -1245,7 +1233,7 @@ discarded."
   (cond ((and overwrite-flag
               (mh-goto-header-field (concat field ":")))
          (insert " " value)
-         (delete-region (point) (mh-line-end-position)))
+         (delete-region (point) (line-end-position)))
         ((and (not overwrite-flag)
               (mh-regexp-in-field-p (concat "\\b" (regexp-quote value) "\\b") 
field))
          ;; Already there, do nothing.
diff --git a/lisp/mh-e/mh-compat.el b/lisp/mh-e/mh-compat.el
index ade80e8..659c435 100644
--- a/lisp/mh-e/mh-compat.el
+++ b/lisp/mh-e/mh-compat.el
@@ -34,44 +34,15 @@
 ;; Please use mh-gnus.el when providing compatibility with different
 ;; versions of Gnus.
 
-;; Items are listed alphabetically (except for mh-require which is
-;; needed sooner it would normally appear).
+;; Items are listed alphabetically.
 
 (eval-when-compile (require 'mh-acros))
 
 (mh-do-in-gnu-emacs
-  (defalias 'mh-require #'require))
-
-(mh-do-in-xemacs
-  (defun mh-require (feature &optional filename noerror)
-    "If feature FEATURE is not loaded, load it from FILENAME.
-If FEATURE is not a member of the list `features', then the feature
-is not loaded; so load the file FILENAME.
-If FILENAME is omitted, the printname of FEATURE is used as the file name.
-If the optional third argument NOERROR is non-nil,
-then return nil if the file is not found instead of signaling an error.
-
-Simulate NOERROR argument in XEmacs which lacks it."
-    (if (not (featurep feature))
-        (if filename
-            (load filename noerror t)
-          (load (format "%s" feature) noerror t)))))
-
-(defun-mh mh-assoc-string assoc-string (key list case-fold)
-  "Like `assoc' but specifically for strings.
-Case is ignored if CASE-FOLD is non-nil.
-This function is used by Emacs versions that lack `assoc-string',
-introduced in Emacs 22."
-  ;; Test for fboundp is solely to silence compiler for Emacs >= 22.1.
-  (if (and case-fold (fboundp 'assoc-ignore-case))
-      (assoc-ignore-case key list)
-    (assoc key list)))
-
-;; For XEmacs.
-(defalias 'mh-cancel-timer
-  (if (fboundp 'cancel-timer)
-      'cancel-timer
-    'delete-itimer))
+  (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.
@@ -90,17 +61,8 @@ the function cell of FUNCs rather than their value cell.
          ,@body)
     `(flet ,bindings ,@body)))
 
-(defun mh-display-color-cells (&optional display)
-  "Return the number of color cells supported by DISPLAY.
-This function is used by XEmacs to return 2 when `device-color-cells'
-or `display-color-cells' returns nil. This happens when compiling or
-running on a tty and causes errors since `display-color-cells' is
-expected to return an integer."
-  (cond ((fboundp 'display-color-cells) ; GNU Emacs, XEmacs 21.5b28
-         (or (display-color-cells display) 2))
-        ((fboundp 'device-color-cells)  ; XEmacs 21.4
-         (or (device-color-cells display) 2))
-        (t 2)))
+(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.
@@ -118,201 +80,46 @@ the completions."
         (t                              ; Emacs 22
          `(display-completion-list ,completions ,common-substring))))
 
-(defmacro mh-face-foreground (face &optional frame inherit)
-  "Return the foreground color name of FACE, or nil if unspecified.
-See documentation for `face-foreground' for a description of the
-arguments FACE, FRAME, and perhaps INHERIT.
-This macro is used by Emacs versions that lack an INHERIT argument,
-introduced in Emacs 22."
-  (if (< emacs-major-version 22)
-      `(face-foreground ,face ,frame)
-    `(face-foreground ,face ,frame ,inherit)))
-
-(defmacro mh-face-background (face &optional frame inherit)
-  "Return the background color name of face, or nil if unspecified.
-See documentation for `face-background' for a description of the
-arguments FACE, FRAME, and INHERIT.
-This macro is used by Emacs versions that lack an INHERIT argument,
-introduced in Emacs 22."
-  (if (< emacs-major-version 22)
-      `(face-background ,face ,frame)
-    `(face-background ,face ,frame ,inherit)))
-
-(defun-mh mh-font-lock-add-keywords font-lock-add-keywords
-  (_mode _keywords &optional _how)
-  "XEmacs does not have `font-lock-add-keywords'.
-This function returns nil on that system.")
-
-(defun-mh mh-image-load-path-for-library
-  image-load-path-for-library (library image &optional path no-error)
-  "Return a suitable search path for images used by LIBRARY.
-
-It searches for IMAGE in `image-load-path' (excluding
-\"`data-directory'/images\") and `load-path', followed by a path
-suitable for LIBRARY, which includes \"../../etc/images\" and
-\"../etc/images\" relative to the library file itself, and then
-in \"`data-directory'/images\".
-
-Then this function returns a list of directories which contains
-first the directory in which IMAGE was found, followed by the
-value of `load-path'. If PATH is given, it is used instead of
-`load-path'.
-
-If NO-ERROR is non-nil and a suitable path can't be found, don't
-signal an error. Instead, return a list of directories as before,
-except that nil appears in place of the image directory.
-
-Here is an example that uses a common idiom to provide
-compatibility with versions of Emacs that lack the variable
-`image-load-path':
-
-    ;; Shush compiler.
-    (defvar image-load-path)
-
-    (let* ((load-path (image-load-path-for-library \"mh-e\" \"mh-logo.xpm\"))
-           (image-load-path (cons (car load-path)
-                                  (when (boundp \\='image-load-path)
-                                    image-load-path))))
-      (mh-tool-bar-folder-buttons-init))"
-  (unless library (error "No library specified"))
-  (unless image   (error "No image specified"))
-  (let (image-directory image-directory-load-path)
-    ;; Check for images in image-load-path or load-path.
-    (let ((img image)
-          (dir (or
-                ;; Images in image-load-path.
-                (mh-image-search-load-path image)
-                ;; Images in load-path.
-                (locate-library image)))
-          parent)
-      ;; Since the image might be in a nested directory (for
-      ;; example, mail/attach.pbm), adjust `image-directory'
-      ;; accordingly.
-      (when dir
-        (setq dir (file-name-directory dir))
-        (while (setq parent (file-name-directory img))
-          (setq img (directory-file-name parent)
-                dir (expand-file-name "../" dir))))
-      (setq image-directory-load-path dir))
-
-    ;; If `image-directory-load-path' isn't Emacs's image directory,
-    ;; it's probably a user preference, so use it. Then use a
-    ;; relative setting if possible; otherwise, use
-    ;; `image-directory-load-path'.
-    (cond
-     ;; User-modified image-load-path?
-     ((and image-directory-load-path
-           (not (equal image-directory-load-path
-                       (file-name-as-directory
-                        (expand-file-name "images" data-directory)))))
-      (setq image-directory image-directory-load-path))
-     ;; Try relative setting.
-     ((let (library-name d1ei d2ei)
-        ;; First, find library in the load-path.
-        (setq library-name (locate-library library))
-        (if (not library-name)
-            (error "Cannot find library %s in load-path" library))
-        ;; And then set image-directory relative to that.
-        (setq
-         ;; Go down 2 levels.
-         d2ei (file-name-as-directory
-               (expand-file-name
-                (concat (file-name-directory library-name) 
"../../etc/images")))
-         ;; Go down 1 level.
-         d1ei (file-name-as-directory
-               (expand-file-name
-                (concat (file-name-directory library-name) "../etc/images"))))
-        (setq image-directory
-              ;; Set it to nil if image is not found.
-              (cond ((file-exists-p (expand-file-name image d2ei)) d2ei)
-                    ((file-exists-p (expand-file-name image d1ei)) d1ei)))))
-     ;; Use Emacs's image directory.
-     (image-directory-load-path
-      (setq image-directory image-directory-load-path))
-     (no-error
-      (message "Could not find image %s for library %s" image library))
-     (t
-      (error "Could not find image %s for library %s" image library)))
-
-    ;; Return an augmented `path' or `load-path'.
-    (nconc (list image-directory)
-           (delete image-directory (copy-sequence (or path load-path))))))
-
-(defun-mh mh-image-search-load-path
-  image-search-load-path (_file &optional _path)
-  "Emacs 21 and XEmacs don't have `image-search-load-path'.
-This function returns nil on those systems."
-  nil)
-
-;; For XEmacs.
-(defalias 'mh-line-beginning-position
-  (if (fboundp 'line-beginning-position)
-      'line-beginning-position
-    'point-at-bol))
-
-;; For XEmacs.
-(defalias 'mh-line-end-position
-  (if (fboundp 'line-end-position)
-      'line-end-position
-    'point-at-eol))
-
-(mh-require 'mailabbrev nil t)
-(defun-mh mh-mail-abbrev-make-syntax-table
-  mail-abbrev-make-syntax-table ()
-  "Emacs 21 and XEmacs don't have `mail-abbrev-make-syntax-table'.
-This function returns nil on those systems."
-  nil)
-
-(defmacro mh-define-obsolete-variable-alias
-  (obsolete-name current-name &optional when docstring)
-  "Make OBSOLETE-NAME a variable alias for CURRENT-NAME and mark it obsolete.
-See documentation for `define-obsolete-variable-alias' for a description
-of the arguments OBSOLETE-NAME, CURRENT-NAME, and perhaps WHEN
-and DOCSTRING. This macro is used by XEmacs that lacks WHEN and
-DOCSTRING arguments."
-  (if (featurep 'xemacs)
-      `(define-obsolete-variable-alias ,obsolete-name ,current-name)
-    `(define-obsolete-variable-alias ,obsolete-name ,current-name ,when 
,docstring)))
-
-(defmacro mh-make-obsolete-variable (obsolete-name current-name &optional when 
access-type)
-  "Make the byte-compiler warn that OBSOLETE-NAME is obsolete.
-See documentation for `make-obsolete-variable' for a description
-of the arguments OBSOLETE-NAME, CURRENT-NAME, and perhaps WHEN
-and ACCESS-TYPE. This macro is used by XEmacs that lacks WHEN and
-ACCESS-TYPE arguments and by Emacs versions that lack ACCESS-TYPE,
-introduced in Emacs 24."
-  (if (featurep 'xemacs)
-      `(make-obsolete-variable ,obsolete-name ,current-name)
-    (if (< emacs-major-version 24)
-        `(make-obsolete-variable ,obsolete-name ,current-name ,when)
-      `(make-obsolete-variable ,obsolete-name ,current-name ,when 
,access-type))))
-
-(defun-mh mh-match-string-no-properties
-  match-string-no-properties (num &optional _string)
-  "Return string of text matched by last search, without text properties.
-This function is used by XEmacs that lacks `match-string-no-properties'.
-The function `buffer-substring-no-properties' is used instead.
-The argument STRING is ignored."
-  (buffer-substring-no-properties
-   (match-beginning num) (match-end num)))
-
-(defun-mh mh-replace-regexp-in-string replace-regexp-in-string
-  (regexp rep string &optional _fixedcase literal _subexp _start)
-  "Replace REGEXP with REP everywhere in STRING and return result.
-This function is used by XEmacs that lacks `replace-regexp-in-string'.
-The function `replace-in-string' is used instead.
-The arguments FIXEDCASE, SUBEXP, and START, used by
-`replace-in-string' are ignored."
-  (if (featurep 'xemacs)                ; silence Emacs compiler
-      (replace-in-string string regexp rep literal)))
-
-(defun-mh mh-test-completion
-  test-completion (_string _collection &optional _predicate)
-  "Return non-nil if STRING is a valid completion.
-XEmacs does not have `test-completion'. This function returns nil
-on that system." nil)
-
-;; Copy of constant from url-util.el in Emacs 22; needed by Emacs 21.
+(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")
+
+(define-obsolete-function-alias 'mh-image-load-path-for-library
+  #'image-load-path-for-library "29.1")
+
+(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
@@ -321,51 +128,21 @@ on that system." nil)
        ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
   "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")
 
-(defun-mh mh-url-hexify-string url-hexify-string (str)
-  "Escape characters in a string.
-This is a copy of `url-hexify-string' from url-util.el in Emacs
-22; needed by Emacs 21."
-  (mapconcat
-   (lambda (char)
-     ;; Fixme: use a char table instead.
-     (if (not (memq char mh-url-unreserved-chars))
-         (if (> char 255)
-               (error "Hexifying multibyte character %s" str)
-           (format "%%%02X" char))
-       (char-to-string char)))
-   str ""))
-
-(defun-mh mh-view-mode-enter
-  view-mode-enter (&optional return-to exit-action)
-  "Enter View mode.
-This function is used by XEmacs that lacks `view-mode-enter'.
-The function `view-mode' is used instead.
-The arguments RETURN-TO and EXIT-ACTION are ignored."
-  ;; Shush compiler.
-  (if return-to nil)
-  (if exit-action nil)
-  (view-mode 1))
-
-(defun-mh mh-window-full-height-p
-  window-full-height-p (&optional _window)
-  "Return non-nil if WINDOW is not the result of a vertical split.
-This function is defined in XEmacs as it lacks
-`window-full-height-p'. The values of the functions
-`window-height' and `frame-height' are compared instead. The
-argument WINDOW is ignored."
-  (= (1+ (window-height))
-     (frame-height)))
+(define-obsolete-function-alias 'mh-window-full-height-p
+  #'window-full-height-p "29.1")
 
 (defmacro mh-write-file-functions ()
-  "Return `write-file-functions' if it exists.
-Otherwise return `local-write-file-hooks'.
-This macro exists purely for compatibility. The former symbol is used
-in Emacs 22 onward while the latter is used in previous versions and
-XEmacs."
-  (if (boundp 'write-file-functions)
-      ''write-file-functions            ;Emacs 22 on
-    ''local-write-file-hooks))          ;XEmacs
+  "Return `write-file-functions'. "
+  (declare (obsolete nil "29.1"))
+  ''write-file-functions)
 
 (provide 'mh-compat)
 
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 9cbc8cf..09f6246 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -88,10 +88,7 @@
 (require 'mh-buffers)
 (require 'mh-compat)
 
-(mh-do-in-xemacs
-  (require 'mh-xemacs))
-
-(mh-font-lock-add-keywords
+(font-lock-add-keywords
  'emacs-lisp-mode
  (eval-when-compile
    `((,(concat "(\\("
@@ -486,7 +483,7 @@ all the strings have been used."
                 (count 0))
             (while (and (not (eobp)) (< count mh-index-max-cmdline-args))
               (push (buffer-substring-no-properties (point)
-                                                    (mh-line-end-position))
+                                                    (line-end-position))
                     arg-list)
               (cl-incf count)
               (forward-line))
@@ -619,10 +616,6 @@ Output is expected to be shown to user, not parsed by 
MH-E."
   ;; The bug wasn't seen in emacs21 but still occurred in XEmacs21.4.
   (mh-exchange-point-and-mark-preserving-active-mark))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar mark-active))
-
 (defun mh-exchange-point-and-mark-preserving-active-mark ()
   "Put the mark where point is now, and point where the mark is now.
 This command works even when the mark is not active, and
@@ -3117,42 +3110,6 @@ of your own choosing."
   :group 'mh-tool-bar
   :package-version '(MH-E . "7.0"))
 
-;; XEmacs has a couple of extra customizations...
-(mh-do-in-xemacs
-  (defcustom-mh mh-xemacs-use-tool-bar-flag mh-xemacs-has-tool-bar-flag
-    "If non-nil, use tool bar.
-
-This option 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."
-    :type 'boolean
-    :group 'mh-tool-bar
-    :set (lambda (symbol value)
-           (if (and (eq value t)
-                    (not mh-xemacs-has-tool-bar-flag))
-               (error "Tool bar not supported"))
-           (set-default symbol value))
-    :package-version '(MH-E . "7.3"))
-
-  (defcustom-mh mh-xemacs-tool-bar-position nil
-    "Tool bar location.
-
-This option controls the placement of the tool bar along the four
-edges of the frame. You can choose from one of \"Same As Default
-Tool Bar\", \"Top\", \"Bottom\", \"Left\", or \"Right\". If this
-variable is set to anything other than \"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."
-    :type '(radio (const :tag "Same As Default Tool Bar" :value nil)
-                  (const :tag "Top" :value top)
-                  (const :tag "Bottom" :value bottom)
-                  (const :tag "Left" :value left)
-                  (const :tag "Right" :value right))
-    :group 'mh-tool-bar
-    :package-version '(MH-E . "7.3")))
-
 
 
 ;;; Hooks (:group 'mh-hooks + group where hook described)
@@ -3282,7 +3239,7 @@ function used to insert the signature with
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(mh-define-obsolete-variable-alias 'mh-kill-folder-suppress-prompt-hooks
+(define-obsolete-variable-alias 'mh-kill-folder-suppress-prompt-hooks
   'mh-kill-folder-suppress-prompt-functions "24.3")
 (defcustom-mh mh-kill-folder-suppress-prompt-functions '(mh-search-p)
   "Abnormal hook run at the beginning of 
\\<mh-folder-mode-map>\\[mh-kill-folder].
@@ -3598,7 +3555,7 @@ specified colors."
 
     (if mh-min-colors-defined-flag
         spec
-      (let ((cells (mh-display-color-cells))
+      (let ((cells (display-color-cells))
             new-spec)
         ;; Remove entries with min-colors, or delete them if we have
         ;; fewer colors than they specify.
diff --git a/lisp/mh-e/mh-folder.el b/lisp/mh-e/mh-folder.el
index 35277ae..ed65395 100644
--- a/lisp/mh-e/mh-folder.el
+++ b/lisp/mh-e/mh-folder.el
@@ -213,141 +213,137 @@ annotation.")
 (defalias 'mh-alt-visit-folder #'mh-visit-folder)
 
 ;; Save the "b" binding for a future `back'. Maybe?
-(gnus-define-keys  mh-folder-mode-map
-  " "           mh-page-msg
-  "!"           mh-refile-or-write-again
-  "'"           mh-toggle-tick
-  ","           mh-header-display
-  "."           mh-alt-show
-  ":"           mh-show-preferred-alternative
-  ";"           mh-toggle-mh-decode-mime-flag
-  ">"           mh-write-msg-to-file
-  "?"           mh-help
-  "E"           mh-extract-rejected-mail
-  "M"           mh-modify
-  "\177"        mh-previous-page
-  "\C-d"        mh-delete-msg-no-motion
-  "\t"          mh-index-next-folder
-  [backtab]     mh-index-previous-folder
-  "\M-\t"       mh-index-previous-folder
-  "\e<"         mh-first-msg
-  "\e>"         mh-last-msg
-  "\ed"         mh-redistribute
-  "\r"          mh-show
-  "^"           mh-alt-refile-msg
-  "c"           mh-copy-msg
-  "d"           mh-delete-msg
-  "e"           mh-edit-again
-  "f"           mh-forward
-  "g"           mh-goto-msg
-  "i"           mh-inc-folder
-  "k"           mh-delete-subject-or-thread
-  "m"           mh-alt-send
-  "n"           mh-next-undeleted-msg
-  "\M-n"        mh-next-unread-msg
-  "o"           mh-refile-msg
-  "p"           mh-previous-undeleted-msg
-  "\M-p"        mh-previous-unread-msg
-  "q"           mh-quit
-  "r"           mh-reply
-  "s"           mh-send
-  "t"           mh-toggle-showing
-  "u"           mh-undo
-  "v"           mh-index-visit-folder
-  "x"           mh-execute-commands
-  "|"           mh-pipe-msg)
-
-(gnus-define-keys (mh-folder-map "F" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "'"           mh-index-ticked-messages
-  "S"           mh-sort-folder
-  "c"           mh-catchup
-  "f"           mh-alt-visit-folder
-  "k"           mh-kill-folder
-  "l"           mh-list-folders
-  "n"           mh-index-new-messages
-  "o"           mh-alt-visit-folder
-  "p"           mh-pack-folder
-  "q"           mh-index-sequenced-messages
-  "r"           mh-rescan-folder
-  "s"           mh-search
-  "u"           mh-undo-folder
-  "v"           mh-visit-folder)
-
-(define-key mh-folder-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-junk-map "J" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-junk-allowlist
-  "b"           mh-junk-blocklist
-  "w"           mh-junk-whitelist)
-
-(gnus-define-keys (mh-ps-print-map "P" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "C"           mh-ps-print-toggle-color
-  "F"           mh-ps-print-toggle-faces
-  "f"           mh-ps-print-msg-file
-  "l"           mh-print-msg
-  "p"           mh-ps-print-msg)
-
-(gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map)
-  "'"           mh-narrow-to-tick
-  "?"           mh-prefix-help
-  "d"           mh-delete-msg-from-seq
-  "k"           mh-delete-seq
-  "l"           mh-list-sequences
-  "n"           mh-narrow-to-seq
-  "p"           mh-put-msg-in-seq
-  "s"           mh-msg-is-in-seq
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-thread-map "T" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "u"           mh-thread-ancestor
-  "p"           mh-thread-previous-sibling
-  "n"           mh-thread-next-sibling
-  "t"           mh-toggle-threads
-  "d"           mh-thread-delete
-  "o"           mh-thread-refile)
-
-(gnus-define-keys (mh-limit-map "/" mh-folder-mode-map)
-  "'"           mh-narrow-to-tick
-  "?"           mh-prefix-help
-  "c"           mh-narrow-to-cc
-  "g"           mh-narrow-to-range
-  "m"           mh-narrow-to-from
-  "s"           mh-narrow-to-subject
-  "t"           mh-narrow-to-to
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "s"           mh-store-msg            ;shar
-  "u"           mh-store-msg)           ;uuencode
-
-(gnus-define-keys (mh-digest-map "D" mh-folder-mode-map)
-  " "           mh-page-digest
-  "?"           mh-prefix-help
-  "\177"        mh-page-digest-backwards
-  "b"           mh-burst-digest)
-
-(gnus-define-keys (mh-mime-map "K" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-mime-save-parts
-  "e"           mh-display-with-external-viewer
-  "i"           mh-folder-inline-mime-part
-  "o"           mh-folder-save-mime-part
-  "t"           mh-toggle-mime-buttons
-  "v"           mh-folder-toggle-mime-part
-  "\t"          mh-next-button
-  [backtab]     mh-prev-button
-  "\M-\t"       mh-prev-button)
-
-(cond
- ((featurep 'xemacs)
-  (define-key mh-folder-mode-map [button2] 'mh-show-mouse))
- (t
-  (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse)))
+(define-keymap :keymap mh-folder-mode-map
+  " "           #'mh-page-msg
+  "!"           #'mh-refile-or-write-again
+  "'"           #'mh-toggle-tick
+  ","           #'mh-header-display
+  "."           #'mh-alt-show
+  ":"           #'mh-show-preferred-alternative
+  ";"           #'mh-toggle-mh-decode-mime-flag
+  ">"           #'mh-write-msg-to-file
+  "?"           #'mh-help
+  "E"           #'mh-extract-rejected-mail
+  "M"           #'mh-modify
+  "\177"        #'mh-previous-page
+  "\C-d"        #'mh-delete-msg-no-motion
+  "\t"          #'mh-index-next-folder
+  [backtab]     #'mh-index-previous-folder
+  "\M-\t"       #'mh-index-previous-folder
+  "\e<"         #'mh-first-msg
+  "\e>"         #'mh-last-msg
+  "\ed"         #'mh-redistribute
+  "\r"          #'mh-show
+  "^"           #'mh-alt-refile-msg
+  "c"           #'mh-copy-msg
+  "d"           #'mh-delete-msg
+  "e"           #'mh-edit-again
+  "f"           #'mh-forward
+  "g"           #'mh-goto-msg
+  "i"           #'mh-inc-folder
+  "k"           #'mh-delete-subject-or-thread
+  "m"           #'mh-alt-send
+  "n"           #'mh-next-undeleted-msg
+  "\M-n"        #'mh-next-unread-msg
+  "o"           #'mh-refile-msg
+  "p"           #'mh-previous-undeleted-msg
+  "\M-p"        #'mh-previous-unread-msg
+  "q"           #'mh-quit
+  "r"           #'mh-reply
+  "s"           #'mh-send
+  "t"           #'mh-toggle-showing
+  "u"           #'mh-undo
+  "v"           #'mh-index-visit-folder
+  "x"           #'mh-execute-commands
+  "|"           #'mh-pipe-msg
+
+  "F" (define-keymap :prefix 'mh-folder-map
+        "?"           #'mh-prefix-help
+        "'"           #'mh-index-ticked-messages
+        "S"           #'mh-sort-folder
+        "c"           #'mh-catchup
+        "f"           #'mh-alt-visit-folder
+        "k"           #'mh-kill-folder
+        "l"           #'mh-list-folders
+        "n"           #'mh-index-new-messages
+        "o"           #'mh-alt-visit-folder
+        "p"           #'mh-pack-folder
+        "q"           #'mh-index-sequenced-messages
+        "r"           #'mh-rescan-folder
+        "s"           #'mh-search
+        "u"           #'mh-undo-folder
+        "v"           #'mh-visit-folder)
+
+  "I" mh-inc-spool-map
+
+  "J" (define-keymap :prefix 'mh-junk-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-junk-allowlist
+        "b"           #'mh-junk-blocklist
+        "w"           #'mh-junk-allowlist)
+
+  "P" (define-keymap :prefix 'mh-ps-print-map
+        "?"           #'mh-prefix-help
+        "C"           #'mh-ps-print-toggle-color
+        "F"           #'mh-ps-print-toggle-faces
+        "f"           #'mh-ps-print-msg-file
+        "l"           #'mh-print-msg
+        "p"           #'mh-ps-print-msg)
+
+  "S" (define-keymap :prefix 'mh-sequence-map
+        "'"           #'mh-narrow-to-tick
+        "?"           #'mh-prefix-help
+        "d"           #'mh-delete-msg-from-seq
+        "k"           #'mh-delete-seq
+        "l"           #'mh-list-sequences
+        "n"           #'mh-narrow-to-seq
+        "p"           #'mh-put-msg-in-seq
+        "s"           #'mh-msg-is-in-seq
+        "w"           #'mh-widen)
+
+  "T" (define-keymap :prefix 'mh-thread-map
+        "?"           #'mh-prefix-help
+        "u"           #'mh-thread-ancestor
+        "p"           #'mh-thread-previous-sibling
+        "n"           #'mh-thread-next-sibling
+        "t"           #'mh-toggle-threads
+        "d"           #'mh-thread-delete
+        "o"           #'mh-thread-refile)
+
+  "/" (define-keymap :prefix 'mh-limit-map
+        "'"           #'mh-narrow-to-tick
+        "?"           #'mh-prefix-help
+        "c"           #'mh-narrow-to-cc
+        "g"           #'mh-narrow-to-range
+        "m"           #'mh-narrow-to-from
+        "s"           #'mh-narrow-to-subject
+        "t"           #'mh-narrow-to-to
+        "w"           #'mh-widen)
+
+  "X" (define-keymap :prefix 'mh-extract-map
+        "?"           #'mh-prefix-help
+        "s"           #'mh-store-msg    ;shar
+        "u"           #'mh-store-msg)   ;uuencode
+
+  "D" (define-keymap :prefix 'mh-digest-map
+        " "           #'mh-page-digest
+        "?"           #'mh-prefix-help
+        "\177"        #'mh-page-digest-backwards
+        "b"           #'mh-burst-digest)
+
+  "K" (define-keymap :prefix 'mh-mime-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-mime-save-parts
+        "e"           #'mh-display-with-external-viewer
+        "i"           #'mh-folder-inline-mime-part
+        "o"           #'mh-folder-save-mime-part
+        "t"           #'mh-toggle-mime-buttons
+        "v"           #'mh-folder-toggle-mime-part
+        "\t"          #'mh-next-button
+        [backtab]     #'mh-prev-button
+        "\M-\t"       #'mh-prev-button)
+
+  [mouse-2] #'mh-show-mouse)
 
 ;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt
 
@@ -512,24 +508,14 @@ font-lock is done highlighting.")
 ;;; MH-Folder Mode
 
 (defmacro mh-remove-xemacs-horizontal-scrollbar ()
-  "Get rid of the horizontal scrollbar that XEmacs insists on putting in."
-  (when (featurep 'xemacs)
-    '(if (and (featurep 'scrollbar)
-              (fboundp 'set-specifier))
-         (set-specifier horizontal-scrollbar-visible-p nil
-                        (cons (current-buffer) nil)))))
+  (declare (obsolete nil "29.1"))
+  nil)
 
 ;; Register mh-folder-mode as supporting which-function-mode...
-(eval-and-compile (mh-require 'which-func nil t))
+(eval-and-compile (require 'which-func nil t))
 (when (and (boundp 'which-func-modes) (listp which-func-modes))
   (add-to-list 'which-func-modes 'mh-folder-mode))
 
-;; Shush compiler.
-(defvar desktop-save-buffer)
-(defvar font-lock-auto-fontify)
-(mh-do-in-xemacs
-  (defvar font-lock-defaults))
-
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-folder-mode 'mode-class 'special)
 
@@ -595,8 +581,6 @@ perform the operation on all messages in that region.
         (mh-tool-bar-folder-buttons-init))
     (if (boundp 'tool-bar-map)
         (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :folder))
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(mh-folder-font-lock-keywords t))
   (make-local-variable 'desktop-save-buffer)
@@ -644,26 +628,17 @@ perform the operation on all messages in that region.
    'imenu-create-index-function 'mh-index-create-imenu-index
                                         ; Setup imenu support
    'mh-previous-window-config nil)      ; Previous window configuration
-  (mh-remove-xemacs-horizontal-scrollbar)
   (setq truncate-lines t)
   (auto-save-mode -1)
   (setq buffer-offer-save t)
-  (mh-make-local-hook (mh-write-file-functions))
-  (add-hook (mh-write-file-functions) #'mh-execute-commands nil t)
+  (add-hook 'write-file-functions #'mh-execute-commands nil t)
   (make-local-variable 'revert-buffer-function)
   (make-local-variable 'hl-line-mode)   ; avoid pollution
   (mh-funcall-if-exists hl-line-mode 1)
   (setq revert-buffer-function #'mh-undo-folder)
   (add-to-list 'minor-mode-alist '(mh-showing-mode " Show"))
-  (mh-do-in-xemacs
-    (easy-menu-add mh-folder-sequence-menu)
-    (easy-menu-add mh-folder-message-menu)
-    (easy-menu-add mh-folder-folder-menu))
   (mh-inc-spool-make)
-  (mh-set-help mh-folder-mode-help-messages)
-  (if (and (featurep 'xemacs)
-           font-lock-auto-fontify)
-      (turn-on-font-lock)))             ; Force font-lock in XEmacs.
+  (mh-set-help mh-folder-mode-help-messages))
 
 
 
diff --git a/lisp/mh-e/mh-funcs.el b/lisp/mh-e/mh-funcs.el
index 4a5e670..0c73aae 100644
--- a/lisp/mh-e/mh-funcs.el
+++ b/lisp/mh-e/mh-funcs.el
@@ -147,7 +147,7 @@ Display the results only if something went wrong."
                                             "-recurse"
                                           "-norecurse"))
         (goto-char (point-min))
-        (mh-view-mode-enter)
+        (view-mode-enter)
         (setq view-exit-action 'kill-buffer)
         (message "Listing folders...done")))))
 
diff --git a/lisp/mh-e/mh-gnus.el b/lisp/mh-e/mh-gnus.el
index cc60f7b..b096cd6 100644
--- a/lisp/mh-e/mh-gnus.el
+++ b/lisp/mh-e/mh-gnus.el
@@ -29,110 +29,50 @@
 (require 'mh-e)
 
 (eval-and-compile
-  (mh-require 'gnus-util nil t)
-  (mh-require 'mm-bodies nil t)
-  (mh-require 'mm-decode nil t)
-  (mh-require 'mm-view nil t)
-  (mh-require 'mml nil t))
+  (require 'gnus-util nil t)
+  (require 'mm-bodies nil t)
+  (require 'mm-decode nil t)
+  (require 'mm-view nil t)
+  (require 'mml nil t))
 
 ;; Copy of function from gnus-util.el.
 ;; TODO This is not in Gnus 5.11.
 (defun-mh mh-gnus-local-map-property gnus-local-map-property (map)
   "Return a list suitable for a text property list specifying keymap MAP."
-  (cond ((featurep 'xemacs) (list 'keymap map))
-        ((>= emacs-major-version 21) (list 'keymap map))
-        (t (list 'local-map map))))
-
-;; Copy of function from mm-decode.el.
-(defun-mh mh-mm-merge-handles mm-merge-handles (handles1 handles2)
-  (append
-   (if (listp (car handles1))
-       handles1
-     (list handles1))
-   (if (listp (car handles2))
-       handles2
-     (list handles2))))
-
-;; Copy of function from mm-decode.el.
-(defun-mh mh-mm-set-handle-multipart-parameter
-  mm-set-handle-multipart-parameter (handle parameter value)
-  ;; HANDLE could be a CTL.
-  (when handle
-    (put-text-property 0 (length (car handle)) parameter value
-                      (car handle))))
-
-;; Copy of function from mm-view.el.
-(defun-mh mh-mm-inline-text-vcard mm-inline-text-vcard (handle)
-  (let ((inhibit-read-only t))
-    (mm-insert-inline
-     handle
-     (concat "\n-- \n"
-            (ignore-errors
-              (if (fboundp 'vcard-pretty-print)
-                  (vcard-pretty-print (mm-get-part handle))
-                (vcard-format-string
-                 (vcard-parse-string (mm-get-part handle)
-                                     'vcard-standard-filter))))))))
-
-;; Function from mm-decode.el used in PGP messages. Just define it with older
-;; Gnus to avoid compiler warning.
-(defun-mh mh-mm-possibly-verify-or-decrypt
-  mm-possibly-verify-or-decrypt (_parts _ctl)
-  nil)
-
-;; Copy of macro in mm-decode.el.
-(defmacro-mh mh-mm-handle-multipart-ctl-parameter
-  mm-handle-multipart-ctl-parameter (handle parameter)
-  `(get-text-property 0 ,parameter (car ,handle)))
-
-;; Copy of function in mm-decode.el.
-(defun-mh mh-mm-readable-p mm-readable-p (handle)
-  "Say whether the content of HANDLE is readable."
-  (and (< (with-current-buffer (mm-handle-buffer handle)
-            (buffer-size)) 10000)
-       (mm-with-unibyte-buffer
-         (mm-insert-part handle)
-         (and (eq (mm-body-7-or-8) '7bit)
-              (not (mh-mm-long-lines-p 76))))))
-
-;; Copy of function in mm-bodies.el.
-(defun-mh mh-mm-long-lines-p mm-long-lines-p (length)
-  "Say whether any of the lines in the buffer is longer than LENGTH."
-  (save-excursion
-    (goto-char (point-min))
-    (end-of-line)
-    (while (and (not (eobp))
-                (not (> (current-column) length)))
-      (forward-line 1)
-      (end-of-line))
-    (and (> (current-column) length)
-         (current-column))))
-
-(defun-mh mh-mm-keep-viewer-alive-p mm-keep-viewer-alive-p (_handle)
-  ;; Released Gnus doesn't keep handles associated with externally displayed
-  ;; MIME parts. So this will always return nil.
-  nil)
-
-(defun-mh mh-mm-destroy-parts mm-destroy-parts (_list)
-  "Older versions of Emacs don't have this function."
-  nil)
-
-(defun-mh mh-mm-uu-dissect-text-parts mm-uu-dissect-text-parts (_handles)
-  "Emacs 21 and XEmacs don't have this function."
-  nil)
-
-;; Copy of function in mml.el.
-(defun-mh mh-mml-minibuffer-read-disposition
-  mml-minibuffer-read-disposition (type &optional default filename)
-  (unless default
-    (setq default (mml-content-disposition type filename)))
-  (let ((disposition (completing-read
-                     (format-prompt "Disposition" default)
-                     '(("attachment") ("inline") (""))
-                     nil t nil nil default)))
-    (if (not (equal disposition ""))
-       disposition
-      default)))
+  (list 'keymap map))
+
+(define-obsolete-function-alias 'mh-mm-merge-handles
+  #'mm-merge-handles "29.1")
+
+(define-obsolete-function-alias 'mh-mm-set-handle-multipart-parameter
+  #'mm-set-handle-multipart-parameter "29.1")
+
+(define-obsolete-function-alias 'mh-mm-inline-text-vcard
+  #'mm-inline-text-vcard "29.1")
+
+(define-obsolete-function-alias 'mh-mm-possibly-verify-or-decrypt
+  #'mm-possibly-verify-or-decrypt "29.1")
+
+(define-obsolete-function-alias 'mh-mm-handle-multipart-ctl-parameter
+  #'mm-handle-multipart-ctl-parameter "29.1")
+
+(define-obsolete-function-alias 'mh-mm-readable-p
+  #'mm-readable-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-long-lines-p
+  #'mm-long-lines-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-keep-viewer-alive-p
+  #'mm-keep-viewer-alive-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-destroy-parts
+  #'mm-destroy-parts "29.1")
+
+(define-obsolete-function-alias 'mh-mm-uu-dissect-text-parts
+  #'mm-uu-dissect-text-parts "29.1")
+
+(define-obsolete-function-alias 'mh-mml-minibuffer-read-disposition
+  #'mml-minibuffer-read-disposition "29.1")
 
 ;; This is mm-save-part from Gnus 5.11 since that function in Emacs
 ;; 21.2 is buggy (the args to read-file-name are incorrect) and the
diff --git a/lisp/mh-e/mh-identity.el b/lisp/mh-e/mh-identity.el
index ceede0d..4e639f1 100644
--- a/lisp/mh-e/mh-identity.el
+++ b/lisp/mh-e/mh-identity.el
@@ -54,8 +54,7 @@ This is normally set as part of an Identity in
 (defun mh-identity-make-menu ()
   "Build the Identity menu.
 This should be called any time `mh-identity-list' or
-`mh-auto-fields-list' change.
-See `mh-identity-add-menu'."
+`mh-auto-fields-list' change."
   (easy-menu-define mh-identity-menu mh-letter-mode-map
     "MH-E identity menu"
     (append
@@ -88,8 +87,8 @@ See `mh-identity-add-menu'."
 (defun mh-identity-add-menu ()
   "Add the current Identity menu.
 See `mh-identity-make-menu'."
-  (if mh-identity-menu
-      (mh-do-in-xemacs (easy-menu-add mh-identity-menu))))
+  (declare (obsolete nil "29.1"))
+  nil)
 
 (defvar mh-identity-local nil
   "Buffer-local variable that holds the identity currently in use.")
@@ -122,7 +121,7 @@ The field name is downcased. If the FIELD begins with the
 character \":\", then it must have a special handler defined in
 `mh-identity-handlers', else return an error since it is not a
 valid header field."
-  (or (cdr (mh-assoc-string field mh-identity-handlers t))
+  (or (cdr (assoc-string field mh-identity-handlers t))
       (and (eq (aref field 0) ?:)
            (error "Field %s not found in `mh-identity-handlers'" field))
       (cdr (assoc ":default" mh-identity-handlers))
diff --git a/lisp/mh-e/mh-letter.el b/lisp/mh-e/mh-letter.el
index ae5b80d..f147b7c 100644
--- a/lisp/mh-e/mh-letter.el
+++ b/lisp/mh-e/mh-letter.el
@@ -114,68 +114,68 @@
 ;;; MH-Letter Keys
 
 ;; If this changes, modify mh-letter-mode-help-messages accordingly, above.
-(gnus-define-keys  mh-letter-mode-map
-  " "                   mh-letter-complete-or-space
-  ","                   mh-letter-confirm-address
-  "\C-c?"               mh-help
-  "\C-c\C-\\"           mh-fully-kill-draft ;if no C-q
-  "\C-c\C-^"            mh-insert-signature ;if no C-s
-  "\C-c\C-c"            mh-send-letter
-  "\C-c\C-d"            mh-insert-identity
-  "\C-c\C-e"            mh-mh-to-mime
-  "\C-c\C-f\C-a"        mh-to-field
-  "\C-c\C-f\C-b"        mh-to-field
-  "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-d"        mh-to-field
-  "\C-c\C-f\C-f"        mh-to-fcc
-  "\C-c\C-f\C-l"        mh-to-field
-  "\C-c\C-f\C-m"        mh-to-field
-  "\C-c\C-f\C-r"        mh-to-field
-  "\C-c\C-f\C-s"        mh-to-field
-  "\C-c\C-f\C-t"        mh-to-field
-  "\C-c\C-fa"           mh-to-field
-  "\C-c\C-fb"           mh-to-field
-  "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fd"           mh-to-field
-  "\C-c\C-ff"           mh-to-fcc
-  "\C-c\C-fl"           mh-to-field
-  "\C-c\C-fm"           mh-to-field
-  "\C-c\C-fr"           mh-to-field
-  "\C-c\C-fs"           mh-to-field
-  "\C-c\C-ft"           mh-to-field
-  "\C-c\C-i"            mh-insert-letter
-  "\C-c\C-m\C-e"        mh-mml-secure-message-encrypt
-  "\C-c\C-m\C-f"        mh-compose-forward
-  "\C-c\C-m\C-g"        mh-mh-compose-anon-ftp
-  "\C-c\C-m\C-i"        mh-compose-insertion
-  "\C-c\C-m\C-m"        mh-mml-to-mime
-  "\C-c\C-m\C-n"        mh-mml-unsecure-message
-  "\C-c\C-m\C-s"        mh-mml-secure-message-sign
-  "\C-c\C-m\C-t"        mh-mh-compose-external-compressed-tar
-  "\C-c\C-m\C-u"        mh-mh-to-mime-undo
-  "\C-c\C-m\C-x"        mh-mh-compose-external-type
-  "\C-c\C-mee"          mh-mml-secure-message-encrypt
-  "\C-c\C-mes"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mf"           mh-compose-forward
-  "\C-c\C-mg"           mh-mh-compose-anon-ftp
-  "\C-c\C-mi"           mh-compose-insertion
-  "\C-c\C-mm"           mh-mml-to-mime
-  "\C-c\C-mn"           mh-mml-unsecure-message
-  "\C-c\C-mse"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mss"          mh-mml-secure-message-sign
-  "\C-c\C-mt"           mh-mh-compose-external-compressed-tar
-  "\C-c\C-mu"           mh-mh-to-mime-undo
-  "\C-c\C-mx"           mh-mh-compose-external-type
-  "\C-c\C-o"            mh-open-line
-  "\C-c\C-q"            mh-fully-kill-draft
-  "\C-c\C-s"            mh-insert-signature
-  "\C-c\C-t"            mh-letter-toggle-header-field-display
-  "\C-c\C-w"            mh-check-whom
-  "\C-c\C-y"            mh-yank-cur-msg
-  "\C-c\M-d"            mh-insert-auto-fields
-  "\M-\t"               mh-letter-complete
-  "\t"                  mh-letter-next-header-field-or-indent
-  [backtab]             mh-letter-previous-header-field)
+(define-keymap :keymap mh-letter-mode-map
+  " "                   #'mh-letter-complete-or-space
+  ","                   #'mh-letter-confirm-address
+  "\C-c?"               #'mh-help
+  "\C-c\C-\\"           #'mh-fully-kill-draft ;if no C-q
+  "\C-c\C-^"            #'mh-insert-signature ;if no C-s
+  "\C-c\C-c"            #'mh-send-letter
+  "\C-c\C-d"            #'mh-insert-identity
+  "\C-c\C-e"            #'mh-mh-to-mime
+  "\C-c\C-f\C-a"        #'mh-to-field
+  "\C-c\C-f\C-b"        #'mh-to-field
+  "\C-c\C-f\C-c"        #'mh-to-field
+  "\C-c\C-f\C-d"        #'mh-to-field
+  "\C-c\C-f\C-f"        #'mh-to-fcc
+  "\C-c\C-f\C-l"        #'mh-to-field
+  "\C-c\C-f\C-m"        #'mh-to-field
+  "\C-c\C-f\C-r"        #'mh-to-field
+  "\C-c\C-f\C-s"        #'mh-to-field
+  "\C-c\C-f\C-t"        #'mh-to-field
+  "\C-c\C-fa"           #'mh-to-field
+  "\C-c\C-fb"           #'mh-to-field
+  "\C-c\C-fc"           #'mh-to-field
+  "\C-c\C-fd"           #'mh-to-field
+  "\C-c\C-ff"           #'mh-to-fcc
+  "\C-c\C-fl"           #'mh-to-field
+  "\C-c\C-fm"           #'mh-to-field
+  "\C-c\C-fr"           #'mh-to-field
+  "\C-c\C-fs"           #'mh-to-field
+  "\C-c\C-ft"           #'mh-to-field
+  "\C-c\C-i"            #'mh-insert-letter
+  "\C-c\C-m\C-e"        #'mh-mml-secure-message-encrypt
+  "\C-c\C-m\C-f"        #'mh-compose-forward
+  "\C-c\C-m\C-g"        #'mh-mh-compose-anon-ftp
+  "\C-c\C-m\C-i"        #'mh-compose-insertion
+  "\C-c\C-m\C-m"        #'mh-mml-to-mime
+  "\C-c\C-m\C-n"        #'mh-mml-unsecure-message
+  "\C-c\C-m\C-s"        #'mh-mml-secure-message-sign
+  "\C-c\C-m\C-t"        #'mh-mh-compose-external-compressed-tar
+  "\C-c\C-m\C-u"        #'mh-mh-to-mime-undo
+  "\C-c\C-m\C-x"        #'mh-mh-compose-external-type
+  "\C-c\C-mee"          #'mh-mml-secure-message-encrypt
+  "\C-c\C-mes"          #'mh-mml-secure-message-signencrypt
+  "\C-c\C-mf"           #'mh-compose-forward
+  "\C-c\C-mg"           #'mh-mh-compose-anon-ftp
+  "\C-c\C-mi"           #'mh-compose-insertion
+  "\C-c\C-mm"           #'mh-mml-to-mime
+  "\C-c\C-mn"           #'mh-mml-unsecure-message
+  "\C-c\C-mse"          #'mh-mml-secure-message-signencrypt
+  "\C-c\C-mss"          #'mh-mml-secure-message-sign
+  "\C-c\C-mt"           #'mh-mh-compose-external-compressed-tar
+  "\C-c\C-mu"           #'mh-mh-to-mime-undo
+  "\C-c\C-mx"           #'mh-mh-compose-external-type
+  "\C-c\C-o"            #'mh-open-line
+  "\C-c\C-q"            #'mh-fully-kill-draft
+  "\C-c\C-s"            #'mh-insert-signature
+  "\C-c\C-t"            #'mh-letter-toggle-header-field-display
+  "\C-c\C-w"            #'mh-check-whom
+  "\C-c\C-y"            #'mh-yank-cur-msg
+  "\C-c\M-d"            #'mh-insert-auto-fields
+  "\M-\t"               #'mh-letter-complete
+  "\t"                  #'mh-letter-next-header-field-or-indent
+  [backtab]             #'mh-letter-previous-header-field)
 
 ;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el.
 
@@ -253,17 +253,13 @@ searching for `mh-mail-header-separator' in the buffer."
     (goto-char (point-min))
     (cond ((equal mh-mail-header-separator "") (point-min))
           ((search-forward (format "\n%s\n" mh-mail-header-separator) nil t)
-           (mh-line-beginning-position 0))
+           (line-beginning-position 0))
           (t (point-min)))))
 
 
 
 ;;; MH-Letter Mode
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar font-lock-defaults))
-
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-letter-mode 'mode-class 'special)
 
@@ -300,14 +296,12 @@ order).
       (mh-tool-bar-letter-buttons-init))
     (if (boundp 'tool-bar-map)
         (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :letter))
   ;; Set the local value of mh-mail-header-separator according to what is
   ;; present in the buffer...
   (set (make-local-variable 'mh-mail-header-separator)
        (save-excursion
          (goto-char (mh-mail-header-end))
-         (buffer-substring-no-properties (point) (mh-line-end-position))))
+         (buffer-substring-no-properties (point) (line-end-position))))
   (make-local-variable 'mail-header-separator)
   (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el
   (mh-set-help mh-letter-mode-help-messages)
@@ -328,12 +322,10 @@ order).
    (t
     ;; ...or the header only
     (setq font-lock-defaults '((mh-show-font-lock-keywords) t))))
-  (mh-do-in-xemacs (easy-menu-add mh-letter-menu))
   ;; Maybe we want to use the existing Mail menu from mail-mode in
   ;; 9.0; in the mean time, let's remove it since the redundancy will
   ;; only produce confusion.
   (define-key mh-letter-mode-map [menu-bar mail] #'undefined)
-  (mh-do-in-xemacs (easy-menu-remove mail-menubar-menu))
   (setq fill-column mh-letter-fill-column)
   (add-hook 'completion-at-point-functions
             #'mh-letter-completion-at-point nil 'local)
@@ -834,7 +826,7 @@ body."
           ((< (point) (progn
                         (beginning-of-line)
                         (re-search-forward mh-letter-header-field-regexp
-                                           (mh-line-end-position) t)
+                                           (line-end-position) t)
                         (point)))
            (beginning-of-line))
           (t (end-of-line)))
diff --git a/lisp/mh-e/mh-limit.el b/lisp/mh-e/mh-limit.el
index 39cf7c5..a002522 100644
--- a/lisp/mh-e/mh-limit.el
+++ b/lisp/mh-e/mh-limit.el
@@ -124,7 +124,7 @@ Use \\<mh-folder-mode-map>\\[mh-widen] to undo this 
command."
   (setq pick-expr
         (let ((case-fold-search t))
           (cl-loop for s in pick-expr
-                   collect (mh-replace-regexp-in-string "re: *" "" s))))
+                   collect (replace-regexp-in-string "re: *" "" s))))
   (mh-narrow-to-header-field 'subject pick-expr))
 
 ;;;###mh-autoload
@@ -214,7 +214,7 @@ Return number of messages put in the sequence:
             (string-equal "" (match-string 3)))
         (progn (message "No subject line")
                nil)
-      (let ((subject (mh-match-string-no-properties 3))
+      (let ((subject (match-string-no-properties 3))
             (list))
         (if (> (length subject) mh-limit-max-subject-size)
             (setq subject (substring subject 0 mh-limit-max-subject-size)))
@@ -222,7 +222,7 @@ Return number of messages put in the sequence:
           (if all
               (goto-char (point-min)))
           (while (re-search-forward mh-scan-subject-regexp nil t)
-            (let ((this-subject (mh-match-string-no-properties 3)))
+            (let ((this-subject (match-string-no-properties 3)))
               (if (> (length this-subject) mh-limit-max-subject-size)
                   (setq this-subject (substring this-subject
                                                 0 mh-limit-max-subject-size)))
@@ -313,7 +313,7 @@ The MH command pick is used to do the match."
       (while (not (eobp))
         (let ((num (ignore-errors
                      (string-to-number
-                      (buffer-substring (point) (mh-line-end-position))))))
+                      (buffer-substring (point) (line-end-position))))))
           (when num (push num msg-list))
           (forward-line))))
     (if (null msg-list)
diff --git a/lisp/mh-e/mh-mime.el b/lisp/mh-e/mh-mime.el
index ad594ae..0dbf8f0 100644
--- a/lisp/mh-e/mh-mime.el
+++ b/lisp/mh-e/mh-mime.el
@@ -141,7 +141,7 @@
                 mm-inline-text-html-renderer)
            (and (boundp 'mm-text-html-renderer) mm-text-html-renderer))))
     ("text/x-vcard"
-     mh-mm-inline-text-vcard
+     mm-inline-text-vcard
      (lambda (handle)
        (or (featurep 'vcard)
            (locate-library "vcard"))))
@@ -171,7 +171,7 @@
     ("audio/.*" ignore ignore)
     ("image/.*" ignore ignore)
     ;; Default to displaying as text
-    (".*" mm-inline-text mh-mm-readable-p))
+    (".*" mm-inline-text mm-readable-p))
   "Alist of media types/tests saying whether types can be displayed inline.")
 
 (defvar mh-mime-save-parts-directory nil
@@ -189,8 +189,6 @@ Set from last use.")
       (set-keymap-parent map mh-show-mode-map))
     (mh-do-in-gnu-emacs
      (define-key map [mouse-2] #'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) #'mh-push-button))
     (dolist (c mh-mime-button-commands)
       (define-key map (cadr c) (car c)))
     map))
@@ -215,8 +213,6 @@ Set from last use.")
     (define-key map "\r" #'mh-press-button)
     (mh-do-in-gnu-emacs
      (define-key map [mouse-2] #'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) #'mh-push-button))
     map))
 
 
@@ -299,14 +295,14 @@ the attachment labeled with that number."
          start end)
     (cond ((and data (not inserted-flag) (not displayed-flag))
            (let ((contents (mm-get-part data)))
-             (add-text-properties (mh-line-beginning-position)
-                                  (mh-line-end-position) '(mh-mime-inserted t))
+             (add-text-properties (line-beginning-position)
+                                  (line-end-position) '(mh-mime-inserted t))
              (setq start (point-marker))
              (forward-line 1)
              (mm-insert-inline data contents)
              (setq end (point-marker))
              (add-text-properties
-              start (progn (goto-char start) (mh-line-end-position))
+              start (progn (goto-char start) (line-end-position))
               `(mh-region (,start . ,end)))))
           ((and data (or inserted-flag displayed-flag))
            (mh-press-button)
@@ -458,10 +454,10 @@ decoding the same message multiple times."
              (setf (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
                    (let ((handles (mm-dissect-buffer nil)))
                      (if handles
-                         (mh-mm-uu-dissect-text-parts handles)
+                         (mm-uu-dissect-text-parts handles)
                        (setq handles (mm-uu-dissect)))
                      (setf (mh-mime-handles (mh-buffer-data))
-                           (mh-mm-merge-handles
+                           (mm-merge-handles
                             handles (mh-mime-handles (mh-buffer-data))))
                      handles))))
 
@@ -532,10 +528,10 @@ parsed and then displayed."
            (if pre-dissected-handles
                (setq handles pre-dissected-handles)
              (if (setq handles (mm-dissect-buffer nil))
-                 (mh-mm-uu-dissect-text-parts handles)
+                 (mm-uu-dissect-text-parts handles)
                (setq handles (mm-uu-dissect)))
              (setf (mh-mime-handles (mh-buffer-data))
-                   (mh-mm-merge-handles handles
+                   (mm-merge-handles handles
                                         (mh-mime-handles (mh-buffer-data))))
              (unless handles
                (mh-decode-message-body)))
@@ -641,7 +637,7 @@ buttons for alternative parts that are usually suppressed."
     (let ((mh-mime-security-button-line-format
            mh-mime-security-button-end-line-format))
       (mh-insert-mime-security-button handle))
-    (mh-mm-set-handle-multipart-parameter
+    (mm-set-handle-multipart-parameter
      handle 'mh-region (cons (point-min-marker) (point-max-marker)))))
 
 (defun mh-mime-display-single (handle)
@@ -752,8 +748,8 @@ buttons for alternative parts that are usually suppressed."
         (mh-insert-mime-button handle id (mm-handle-displayed-p handle))
         (goto-char point)
         (when region
-          (add-text-properties (mh-line-beginning-position)
-                               (mh-line-end-position)
+          (add-text-properties (line-beginning-position)
+                               (line-end-position)
                                `(mh-region ,region)))))))
 
 (defun mh-mime-part-index (handle)
@@ -777,20 +773,13 @@ This is only useful if a Content-Disposition header is 
not present."
                                         ; this only tells us if the image is
                                         ; something that emacs can display
          (let ((image (mm-get-image handle)))
-           (or (mh-do-in-xemacs
-                 (and (mh-funcall-if-exists glyphp image)
-                      (< (glyph-width image)
-                         (or mh-max-inline-image-width (window-pixel-width)))
-                      (< (glyph-height image)
-                         (or mh-max-inline-image-height
-                             (window-pixel-height)))))
-               (mh-do-in-gnu-emacs
-                 (let ((size (and (fboundp 'image-size) (image-size image))))
-                   (and size
-                        (< (cdr size) (or mh-max-inline-image-height
-                                          (1- (window-height))))
-                        (< (car size) (or mh-max-inline-image-width
-                                          (window-width)))))))))))
+           (mh-do-in-gnu-emacs
+             (let ((size (and (fboundp 'image-size) (image-size image))))
+               (and size
+                    (< (cdr size) (or mh-max-inline-image-height
+                                      (1- (window-height))))
+                    (< (car size) (or mh-max-inline-image-width
+                                      (window-width))))))))))
 
 (defun mh-inline-vcard-p (handle)
   "Decide if HANDLE is a vcard that must be displayed inline."
@@ -821,19 +810,12 @@ being used to highlight the signature in a MIME part."
         (mh-do-in-gnu-emacs
           (let ((ov (make-overlay (point) (point-max))))
             (overlay-put ov 'face 'mh-show-signature)
-            (overlay-put ov 'evaporate t)))
-        (mh-do-in-xemacs
-          (set-extent-property (make-extent (point) (point-max))
-                               'face 'mh-show-signature))))))
+            (overlay-put ov 'evaporate t)))))))
 
 
 
 ;;; Button Display
 
-;; Shush compiler.
-(mh-do-in-xemacs
- (defvar ov))
-
 (defun mh-insert-mime-button (handle index displayed)
   "Insert MIME button for HANDLE.
 INDEX is the part number that will be DISPLAYED. It is also used
@@ -877,16 +859,12 @@ by commands like \"K v\" which operate on individual MIME 
parts."
      :button-keymap mh-mime-button-map
      :help-echo
      "Mouse-2 click or press RET (in show buffer) to toggle display")
-    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-      (mh-funcall-if-exists overlay-put ov 'evaporate t))))
-
-;; Shush compiler.
-(defvar mm-verify-function-alist)       ; < Emacs 22
-(defvar mm-decrypt-function-alist)      ; < Emacs 22
+    (dolist (ov (overlays-in begin end))
+      (overlay-put ov 'evaporate t))))
 
 (defun mh-insert-mime-security-button (handle)
   "Display buttons for PGP message, HANDLE."
-  (let* ((protocol (mh-mm-handle-multipart-ctl-parameter handle 'protocol))
+  (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
          (crypto-type (or (nth 2 (assoc protocol mm-verify-function-alist))
                           (nth 2 (assoc protocol mm-decrypt-function-alist))
                           "Unknown"))
@@ -897,10 +875,10 @@ by commands like \"K v\" which operate on individual MIME 
parts."
                              (if (equal (car handle) "multipart/signed")
                                  " Signed" " Encrypted")
                              " Part"))
-               (info (or (mh-mm-handle-multipart-ctl-parameter
+               (info (or (mm-handle-multipart-ctl-parameter
                           handle 'gnus-info)
                          "Undecided"))
-               (details (mh-mm-handle-multipart-ctl-parameter
+               (details (mm-handle-multipart-ctl-parameter
                          handle 'gnus-details))
                pressed-details)
       (setq details (if details (concat "\n" details) ""))
@@ -923,8 +901,8 @@ by commands like \"K v\" which operate on individual MIME 
parts."
                              :button-keymap mh-mime-security-button-map
                              :button-face face
                              :help-echo "Mouse-2 click or press RET (in show 
buffer) to see security details.")
-      (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-        (mh-funcall-if-exists overlay-put ov 'evaporate t))
+      (dolist (ov (overlays-in begin end))
+        (overlay-put ov 'evaporate t))
       (when (equal info "Failed")
         (let* ((type (if (equal (car handle) "multipart/signed")
                          "verification" "decryption"))
@@ -1081,7 +1059,7 @@ This is only called in recent versions of Gnus. The MIME 
handles
 are stored in data structures corresponding to MH-E folder buffer
 FOLDER instead of in Gnus (as in the original). The MIME part,
 HANDLE is associated with the undisplayer FUNCTION."
-  (if (mh-mm-keep-viewer-alive-p handle)
+  (if (mm-keep-viewer-alive-p handle)
       (let ((new-handle (copy-sequence handle)))
         (mm-handle-set-undisplayer new-handle function)
         (mm-handle-set-undisplayer handle nil)
@@ -1091,19 +1069,19 @@ HANDLE is associated with the undisplayer FUNCTION."
 
 (defun mh-mime-security-press-button (handle)
   "Callback from security button for part HANDLE."
-  (if (mh-mm-handle-multipart-ctl-parameter handle 'gnus-info)
+  (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
       (mh-mime-security-show-details handle)
-    (let ((region (mh-mm-handle-multipart-ctl-parameter handle 'mh-region))
+    (let ((region (mm-handle-multipart-ctl-parameter handle 'mh-region))
           point)
       (setq point (point))
       (goto-char (car region))
       (delete-region (car region) (cdr region))
-      (with-current-buffer (mh-mm-handle-multipart-ctl-parameter handle 
'buffer)
+      (with-current-buffer (mm-handle-multipart-ctl-parameter handle 'buffer)
         (let* ((mm-verify-option 'known)
                (mm-decrypt-option 'known)
-               (new (mh-mm-possibly-verify-or-decrypt (cdr handle) handle)))
+               (new (mm-possibly-verify-or-decrypt (cdr handle) handle)))
           (unless (eq new (cdr handle))
-            (mh-mm-destroy-parts (cdr handle))
+            (mm-destroy-parts (cdr handle))
             (setcdr handle new))))
       (mh-mime-display-security handle)
       (goto-char point))))
@@ -1113,7 +1091,7 @@ HANDLE is associated with the undisplayer FUNCTION."
 ;; to be no way of getting rid of the inserted text.
 (defun mh-mime-security-show-details (handle)
   "Toggle display of detailed security info for HANDLE."
-  (let ((details (mh-mm-handle-multipart-ctl-parameter handle 'gnus-details)))
+  (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
     (when details
       (let ((mh-mime-security-button-pressed
              (not (get-text-property (point) 'mh-button-pressed)))
@@ -1158,7 +1136,7 @@ this ;-)"
 (defun mh-display-smileys ()
   "Display smileys."
   (when (and mh-graphical-smileys-flag (mh-small-show-buffer-p))
-    (mh-funcall-if-exists smiley-region (point-min) (point-max))))
+    (smiley-region (point-min) (point-max))))
 
 ;;;###mh-autoload
 (defun mh-display-emphasis ()
@@ -1303,7 +1281,7 @@ automatically."
          (type (mh-minibuffer-read-type file))
          (description (mml-minibuffer-read-description))
          (dispos (or disposition
-                     (mh-mml-minibuffer-read-disposition type))))
+                     (mml-minibuffer-read-disposition type))))
     (mml-insert-empty-tag 'part 'type type 'filename file
                           'disposition dispos 'description description)))
 
@@ -1507,9 +1485,9 @@ This function will quote all such characters."
     (goto-char (point-min))
     (while (re-search-forward "^#" nil t)
       (beginning-of-line)
-      (unless (mh-mh-directive-present-p (point) (mh-line-end-position))
+      (unless (mh-mh-directive-present-p (point) (line-end-position))
         (insert "#"))
-      (goto-char (mh-line-end-position)))))
+      (goto-char (line-end-position)))))
 
 ;;;###mh-autoload
 (defun mh-mh-to-mime-undo (noconfirm)
@@ -1695,7 +1673,7 @@ buffer, while END defaults to the end of the buffer."
       (goto-char begin)
       (while (re-search-forward "^#" end t)
         (let ((s (buffer-substring-no-properties
-                  (point) (mh-line-end-position))))
+                  (point) (line-end-position))))
           (cond ((equal s ""))
                 ((string-match "^forw[ \t\n]+" s)
                  (cl-return-from search-for-mh-directive t))
@@ -1814,10 +1792,9 @@ initialized. Always use the command 
`mh-have-file-command'.")
 (defun mh-mime-cleanup ()
   "Free the decoded MIME parts."
   (let ((mime-data (gethash (current-buffer) mh-globals-hash)))
-    ;; This is for Emacs, what about XEmacs?
-    (mh-funcall-if-exists remove-images (point-min) (point-max))
+    (remove-images (point-min) (point-max))
     (when mime-data
-      (mh-mm-destroy-parts (mh-mime-handles mime-data))
+      (mm-destroy-parts (mh-mime-handles mime-data))
       (remhash (current-buffer) mh-globals-hash))))
 
 ;;;###mh-autoload
@@ -1825,7 +1802,7 @@ initialized. Always use the command 
`mh-have-file-command'.")
   "Free MIME data for externally displayed MIME parts."
   (let ((mime-data (mh-buffer-data)))
     (when mime-data
-      (mh-mm-destroy-parts (mh-mime-handles mime-data)))
+      (mm-destroy-parts (mh-mime-handles mime-data)))
     (remhash (current-buffer) mh-globals-hash)))
 
 (provide 'mh-mime)
diff --git a/lisp/mh-e/mh-search.el b/lisp/mh-e/mh-search.el
index e03c9dc..23f0f5a 100644
--- a/lisp/mh-e/mh-search.el
+++ b/lisp/mh-e/mh-search.el
@@ -42,6 +42,7 @@
 ;;; Code:
 
 (require 'mh-e)
+(require 'mh-letter)
 
 (require 'gnus-util)
 (require 'imenu)
@@ -318,10 +319,6 @@ folder containing the index search results."
                  (cl-loop for msg-hash being the hash-values of mh-index-data
                           count (> (hash-table-count msg-hash) 0)))))))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar pick-folder))                    ;FIXME: Why?
-
 (defun mh-search-folder (folder window-config)
   "Search FOLDER for messages matching a pattern.
 
@@ -356,13 +353,13 @@ configuration and is used when the search folder is 
dismissed."
   (goto-char (point-min))
   (dotimes (_ 5)
     (add-text-properties (point) (1+ (point)) '(front-sticky t))
-    (add-text-properties (- (mh-line-end-position) 2)
-                         (1- (mh-line-end-position))
+    (add-text-properties (- (line-end-position) 2)
+                         (1- (line-end-position))
                          '(rear-nonsticky t))
-    (add-text-properties (point) (1- (mh-line-end-position)) '(read-only t))
+    (add-text-properties (point) (1- (line-end-position)) '(read-only t))
     (forward-line))
   (add-text-properties (point) (1+ (point)) '(front-sticky t))
-  (add-text-properties (point) (1- (mh-line-end-position)) '(read-only t))
+  (add-text-properties (point) (1- (line-end-position)) '(read-only t))
   (goto-char (point-max)))
 
 ;; Sequence Searches
@@ -522,10 +519,10 @@ group of results."
       (cond ((and (bolp) (eolp))
              (ignore-errors (forward-line -1))
              (setq msg (mh-get-msg-num t)))
-            ((equal (char-after (mh-line-beginning-position)) ?+)
+            ((equal (char-after (line-beginning-position)) ?+)
              (setq folder (buffer-substring-no-properties
-                           (mh-line-beginning-position)
-                           (mh-line-end-position))))
+                           (line-beginning-position)
+                           (line-end-position))))
             (t (setq msg (mh-get-msg-num t)))))
     (when (not folder)
       (setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
@@ -552,20 +549,20 @@ group of results."
 ;;; MH-Search Keys
 
 ;; If this changes, modify mh-search-mode-help-messages accordingly, below.
-(gnus-define-keys  mh-search-mode-map
-  "\C-c?"               mh-help
-  "\C-c\C-c"            mh-index-do-search
-  "\C-c\C-p"            mh-pick-do-search
-  "\C-c\C-f\C-b"        mh-to-field
-  "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-m"        mh-to-field
-  "\C-c\C-f\C-s"        mh-to-field
-  "\C-c\C-f\C-t"        mh-to-field
-  "\C-c\C-fb"           mh-to-field
-  "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fm"           mh-to-field
-  "\C-c\C-fs"           mh-to-field
-  "\C-c\C-ft"           mh-to-field)
+(define-keymap :keymap mh-search-mode-map
+  "\C-c?"               #'mh-help
+  "\C-c\C-c"            #'mh-index-do-search
+  "\C-c\C-p"            #'mh-pick-do-search
+  "\C-c\C-f\C-b"        #'mh-to-field
+  "\C-c\C-f\C-c"        #'mh-to-field
+  "\C-c\C-f\C-m"        #'mh-to-field
+  "\C-c\C-f\C-s"        #'mh-to-field
+  "\C-c\C-f\C-t"        #'mh-to-field
+  "\C-c\C-fb"           #'mh-to-field
+  "\C-c\C-fc"           #'mh-to-field
+  "\C-c\C-fm"           #'mh-to-field
+  "\C-c\C-fs"           #'mh-to-field
+  "\C-c\C-ft"           #'mh-to-field)
 
 
 
@@ -616,7 +613,6 @@ The hook `mh-search-mode-hook' is called upon entry to this 
mode.
 
 \\{mh-search-mode-map}"
 
-  (mh-do-in-xemacs (easy-menu-add mh-pick-menu))
   (mh-set-help mh-search-mode-help-messages))
 
 
@@ -653,13 +649,13 @@ The cdr of the element is the pattern to search."
           start begin)
       (goto-char (point-min))
       (while (not (eobp))
-        (if (search-forward "--------" (mh-line-end-position) t)
+        (if (search-forward "--------" (line-end-position) t)
             (setq in-body-flag t)
           (beginning-of-line)
           (setq begin (point))
           (setq start (if in-body-flag
                           (point)
-                        (search-forward ":" (mh-line-end-position) t)
+                        (search-forward ":" (line-end-position) t)
                         (point)))
           (push (cons (and (not in-body-flag)
                            (intern (downcase
@@ -667,7 +663,7 @@ The cdr of the element is the pattern to search."
                                      begin (1- start)))))
                       (mh-index-parse-search-regexp
                        (buffer-substring-no-properties
-                        start (mh-line-end-position))))
+                        start (line-end-position))))
                 pattern-list))
         (forward-line))
       pattern-list)))
@@ -977,8 +973,8 @@ is used to search."
           (cl-return nil))
         (when (equal (char-after (point)) ?#)
           (cl-return 'error))
-        (let* ((start (search-forward " " (mh-line-end-position) t))
-               (end (search-forward " " (mh-line-end-position) t)))
+        (let* ((start (search-forward " " (line-end-position) t))
+               (end (search-forward " " (line-end-position) t)))
           (unless (and start end)
             (cl-return 'error))
           (setq end (1- end))
@@ -1056,7 +1052,7 @@ SEARCH-REGEXP-LIST is used to search."
           (cl-return 'error))
         (let ((start (point))
               end msg-start)
-          (setq end (mh-line-end-position))
+          (setq end (line-end-position))
           (unless (search-forward mh-mairix-folder end t)
             (cl-return 'error))
           (goto-char (match-beginning 0))
@@ -1197,7 +1193,7 @@ is used to search."
       (cl-block nil
         (when (eobp) (cl-return nil))
         (let ((file-name (buffer-substring-no-properties
-                          (point) (mh-line-end-position))))
+                          (point) (line-end-position))))
           (unless (equal (string-match mh-namazu-folder file-name) 0)
             (cl-return 'error))
           (unless (file-exists-p file-name)
@@ -1245,17 +1241,17 @@ is used to search."
   (prog1
       (cl-block nil
         (when (eobp) (cl-return nil))
-        (when (search-forward-regexp "^\\+" (mh-line-end-position) t)
+        (when (search-forward-regexp "^\\+" (line-end-position) t)
           (setq mh-index-pick-folder
-                (buffer-substring-no-properties (mh-line-beginning-position)
-                                                (mh-line-end-position)))
+                (buffer-substring-no-properties (line-beginning-position)
+                                                (line-end-position)))
           (cl-return 'error))
-        (unless (search-forward-regexp "^[1-9][0-9]*$" (mh-line-end-position) 
t)
+        (unless (search-forward-regexp "^[1-9][0-9]*$" (line-end-position) t)
           (cl-return 'error))
         (list mh-index-pick-folder
               (string-to-number
-               (buffer-substring-no-properties (mh-line-beginning-position)
-                                               (mh-line-end-position)))
+               (buffer-substring-no-properties (line-beginning-position)
+                                               (line-end-position)))
               nil))
     (forward-line)))
 
@@ -1332,8 +1328,8 @@ record is invalid return `error'."
       (cl-block nil
         (when (eobp)
           (cl-return nil))
-        (let ((eol-pos (mh-line-end-position))
-              (bol-pos (mh-line-beginning-position))
+        (let ((eol-pos (line-end-position))
+              (bol-pos (line-beginning-position))
               folder-start msg-end)
           (goto-char bol-pos)
           (unless (search-forward mh-user-path eol-pos t)
@@ -1415,10 +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 (mh-require 'which-func nil t))
-
-;; Shush compiler.
-(defvar which-func-mode)                ; < Emacs 22, XEmacs
+(eval-and-compile (require 'which-func nil t))
 
 ;;;###mh-autoload
 (defun mh-index-create-imenu-index ()
@@ -1432,7 +1425,7 @@ being the list of messages originally from that folder."
         (save-excursion
           (beginning-of-line)
           (push (cons (buffer-substring-no-properties
-                       (point) (mh-line-end-position))
+                       (point) (line-end-position))
                       (point-marker))
                 alist)))
       (setq imenu--index-alist (nreverse alist)))))
@@ -1717,7 +1710,7 @@ folder, is removed from `mh-index-data'."
                         "-format" "%{x-mhe-checksum}\n" folder msg)
     (goto-char (point-min))
     (string-equal (buffer-substring-no-properties
-                   (point) (mh-line-end-position))
+                   (point) (line-end-position))
                   checksum)))
 
 
@@ -1826,8 +1819,8 @@ PROC is used to convert the value to actual data."
 
 (defun mh-md5sum-parser ()
   "Parse md5sum output."
-  (let ((begin (mh-line-beginning-position))
-        (end (mh-line-end-position))
+  (let ((begin (line-beginning-position))
+        (end (line-end-position))
         first-space last-slash)
     (setq first-space (search-forward " " end t))
     (goto-char end)
@@ -1840,8 +1833,8 @@ PROC is used to convert the value to actual data."
 
 (defun mh-openssl-parser ()
   "Parse openssl output."
-  (let ((begin (mh-line-beginning-position))
-        (end (mh-line-end-position))
+  (let ((begin (line-beginning-position))
+        (end (line-end-position))
         last-space last-slash)
     (goto-char end)
     (setq last-space (search-backward " " begin t))
@@ -1874,7 +1867,7 @@ origin-index) map is updated too."
       (let (msg checksum)
         (while (not (eobp))
           (setq msg (buffer-substring-no-properties
-                     (point) (mh-line-end-position)))
+                     (point) (line-end-position)))
           (forward-line)
           (save-excursion
             (cond ((not (string-match "^[0-9]*$" msg)))
@@ -1885,7 +1878,7 @@ origin-index) map is updated too."
                   (t
                    ;; update maps
                    (setq checksum (buffer-substring-no-properties
-                                   (point) (mh-line-end-position)))
+                                   (point) (line-end-position)))
                    (let ((msg (string-to-number msg)))
                      (set-buffer folder)
                      (mh-index-update-single-msg msg checksum origin-map)))))
diff --git a/lisp/mh-e/mh-seq.el b/lisp/mh-e/mh-seq.el
index a50319a..c8df75d 100644
--- a/lisp/mh-e/mh-seq.el
+++ b/lisp/mh-e/mh-seq.el
@@ -167,7 +167,7 @@ The list appears in a buffer named \"*MH-E Sequences*\"."
             (insert "\n"))
           (setq seq-list (cdr seq-list)))
         (goto-char (point-min))
-        (mh-view-mode-enter)
+        (view-mode-enter)
         (setq view-exit-action 'kill-buffer)
         (message "Listing sequences...done")))))
 
@@ -193,11 +193,6 @@ MESSAGE appears."
                         (mh-list-to-string (mh-seq-containing-msg message t))
                         " "))))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar tool-bar-mode))
-(defvar tool-bar-map)
-
 ;;;###mh-autoload
 (defun mh-narrow-to-seq (sequence)
   "Restrict display to messages in SEQUENCE.
@@ -736,7 +731,7 @@ completion is over."
     (cl-multiple-value-bind (folder unseen total)
         (cl-values-list
          (mh-parse-flist-output-line
-          (buffer-substring (point) (mh-line-end-position))))
+          (buffer-substring (point) (line-end-position))))
       (list total unseen folder))))
 
 (defun mh-folder-size-folder (folder)
@@ -764,7 +759,7 @@ folders whose names end with a `+' character."
       (when (search-backward " out of " (point-min) t)
         (setq total (string-to-number
                      (buffer-substring-no-properties
-                      (match-end 0) (mh-line-end-position))))
+                      (match-end 0) (line-end-position))))
         (when (search-backward " in sequence " (point-min) t)
           (setq p (point))
           (when (search-backward " has " (point-min) t)
@@ -942,7 +937,7 @@ font-lock is turned on."
             ;; the case of user sequences.
             (mh-notate nil nil mh-cmd-note)
             (when font-lock-mode
-              (font-lock-fontify-region (point) (mh-line-end-position))))
+              (font-lock-fontify-region (point) (line-end-position))))
         (forward-char (+ mh-cmd-note mh-scan-field-destination-offset))
         (let ((stack (gethash msg mh-sequence-notation-history)))
           (setf (gethash msg mh-sequence-notation-history)
diff --git a/lisp/mh-e/mh-show.el b/lisp/mh-e/mh-show.el
index 803f07e..25b83b2 100644
--- a/lisp/mh-e/mh-show.el
+++ b/lisp/mh-e/mh-show.el
@@ -144,7 +144,7 @@ displayed."
             (if (not clean-message-header)
                 (mh-start-of-uncleaned-message)))
         (mh-display-msg msg folder)))
-    (unless (mh-window-full-height-p) ; not vertically split
+    (unless (window-full-height-p) ; not vertically split
       (shrink-window (- (window-height) (or mh-summary-height
                                             (mh-summary-height)))))
     (mh-recenter nil)
@@ -363,11 +363,11 @@ still visible.\n")
                         folder-buffer)
            (delete-other-windows))
          (mh-goto-cur-msg t)
-         (mh-funcall-if-exists deactivate-mark)
+         (deactivate-mark)
          (unwind-protect
              (prog1 (call-interactively (function ,original-function))
                (setq normal-exit t))
-           (mh-funcall-if-exists deactivate-mark)
+           (deactivate-mark)
            (when (eq major-mode 'mh-folder-mode)
              (mh-funcall-if-exists hl-line-highlight))
            (cond ((not normal-exit)
@@ -562,132 +562,132 @@ still visible.\n")
 
 ;;; MH-Show Keys
 
-(gnus-define-keys mh-show-mode-map
-  " "    mh-show-page-msg
-  "!"    mh-show-refile-or-write-again
-  "'"    mh-show-toggle-tick
-  ","    mh-show-header-display
-  "."    mh-show-show
-  ":"    mh-show-show-preferred-alternative
-  ">"    mh-show-write-message-to-file
-  "?"    mh-help
-  "E"    mh-show-extract-rejected-mail
-  "M"    mh-show-modify
-  "\177" mh-show-previous-page
-  "\C-d" mh-show-delete-msg-no-motion
-  "\t"   mh-show-next-button
-  [backtab] mh-show-prev-button
-  "\M-\t" mh-show-prev-button
-  "\ed"  mh-show-redistribute
-  "^"    mh-show-refile-msg
-  "c"    mh-show-copy-msg
-  "d"    mh-show-delete-msg
-  "e"    mh-show-edit-again
-  "f"    mh-show-forward
-  "g"    mh-show-goto-msg
-  "i"    mh-show-inc-folder
-  "k"    mh-show-delete-subject-or-thread
-  "m"    mh-show-send
-  "n"    mh-show-next-undeleted-msg
-  "\M-n" mh-show-next-unread-msg
-  "o"    mh-show-refile-msg
-  "p"    mh-show-previous-undeleted-msg
-  "\M-p" mh-show-previous-unread-msg
-  "q"    mh-show-quit
-  "r"    mh-show-reply
-  "s"    mh-show-send
-  "t"    mh-show-toggle-showing
-  "u"    mh-show-undo
-  "x"    mh-show-execute-commands
-  "v"    mh-show-index-visit-folder
-  "|"    mh-show-pipe-msg)
-
-(gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "'"    mh-index-ticked-messages
-  "S"    mh-show-sort-folder
-  "c"    mh-show-catchup
-  "f"    mh-show-visit-folder
-  "k"    mh-show-kill-folder
-  "l"    mh-show-list-folders
-  "n"    mh-index-new-messages
-  "o"    mh-show-visit-folder
-  "p"    mh-show-pack-folder
-  "q"    mh-show-index-sequenced-messages
-  "r"    mh-show-rescan-folder
-  "s"    mh-search
-  "t"    mh-show-toggle-threads
-  "u"    mh-show-undo-folder
-  "v"    mh-show-visit-folder)
-
-(gnus-define-keys (mh-show-sequence-map "S" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "d"    mh-show-delete-msg-from-seq
-  "k"    mh-show-delete-seq
-  "l"    mh-show-list-sequences
-  "n"    mh-show-narrow-to-seq
-  "p"    mh-show-put-msg-in-seq
-  "s"    mh-show-msg-is-in-seq
-  "w"    mh-show-widen)
-
-(define-key mh-show-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "a"    mh-show-junk-allowlist
-  "b"    mh-show-junk-blocklist
-  "w"    mh-show-junk-whitelist)
-
-(gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map)
-  "?"   mh-prefix-help
-  "C"   mh-show-ps-print-toggle-color
-  "F"   mh-show-ps-print-toggle-faces
-  "f"   mh-show-ps-print-msg-file
-  "l"   mh-show-print-msg
-  "p"   mh-show-ps-print-msg)
-
-(gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "u"    mh-show-thread-ancestor
-  "p"    mh-show-thread-previous-sibling
-  "n"    mh-show-thread-next-sibling
-  "t"    mh-show-toggle-threads
-  "d"    mh-show-thread-delete
-  "o"    mh-show-thread-refile)
-
-(gnus-define-keys (mh-show-limit-map "/" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "c"    mh-show-narrow-to-cc
-  "g"    mh-show-narrow-to-range
-  "m"    mh-show-narrow-to-from
-  "s"    mh-show-narrow-to-subject
-  "t"    mh-show-narrow-to-to
-  "w"    mh-show-widen)
-
-(gnus-define-keys (mh-show-extract-map "X" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "s"    mh-show-store-msg
-  "u"    mh-show-store-msg)
-
-(gnus-define-keys (mh-show-digest-map "D" mh-show-mode-map)
-  "?"    mh-prefix-help
-  " "    mh-show-page-digest
-  "\177" mh-show-page-digest-backwards
-  "b"    mh-show-burst-digest)
-
-(gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-mime-save-parts
-  "e"           mh-show-display-with-external-viewer
-  "v"           mh-show-toggle-mime-part
-  "o"           mh-show-save-mime-part
-  "i"           mh-show-inline-mime-part
-  "t"           mh-show-toggle-mime-buttons
-  "\t"          mh-show-next-button
-  [backtab]     mh-show-prev-button
-  "\M-\t"       mh-show-prev-button)
+(define-keymap :keymap mh-show-mode-map
+  " "    #'mh-show-page-msg
+  "!"    #'mh-show-refile-or-write-again
+  "'"    #'mh-show-toggle-tick
+  ","    #'mh-show-header-display
+  "."    #'mh-show-show
+  ":"    #'mh-show-show-preferred-alternative
+  ">"    #'mh-show-write-message-to-file
+  "?"    #'mh-help
+  "E"    #'mh-show-extract-rejected-mail
+  "M"    #'mh-show-modify
+  "\177" #'mh-show-previous-page
+  "\C-d" #'mh-show-delete-msg-no-motion
+  "\t"   #'mh-show-next-button
+  [backtab] #'mh-show-prev-button
+  "\M-\t" #'mh-show-prev-button
+  "\ed"  #'mh-show-redistribute
+  "^"    #'mh-show-refile-msg
+  "c"    #'mh-show-copy-msg
+  "d"    #'mh-show-delete-msg
+  "e"    #'mh-show-edit-again
+  "f"    #'mh-show-forward
+  "g"    #'mh-show-goto-msg
+  "i"    #'mh-show-inc-folder
+  "k"    #'mh-show-delete-subject-or-thread
+  "m"    #'mh-show-send
+  "n"    #'mh-show-next-undeleted-msg
+  "\M-n" #'mh-show-next-unread-msg
+  "o"    #'mh-show-refile-msg
+  "p"    #'mh-show-previous-undeleted-msg
+  "\M-p" #'mh-show-previous-unread-msg
+  "q"    #'mh-show-quit
+  "r"    #'mh-show-reply
+  "s"    #'mh-show-send
+  "t"    #'mh-show-toggle-showing
+  "u"    #'mh-show-undo
+  "x"    #'mh-show-execute-commands
+  "v"    #'mh-show-index-visit-folder
+  "|"    #'mh-show-pipe-msg
+
+  "F" (define-keymap :prefix 'mh-show-folder-map
+        "?"    #'mh-prefix-help
+        "'"    #'mh-index-ticked-messages
+        "S"    #'mh-show-sort-folder
+        "c"    #'mh-show-catchup
+        "f"    #'mh-show-visit-folder
+        "k"    #'mh-show-kill-folder
+        "l"    #'mh-show-list-folders
+        "n"    #'mh-index-new-messages
+        "o"    #'mh-show-visit-folder
+        "p"    #'mh-show-pack-folder
+        "q"    #'mh-show-index-sequenced-messages
+        "r"    #'mh-show-rescan-folder
+        "s"    #'mh-search
+        "t"    #'mh-show-toggle-threads
+        "u"    #'mh-show-undo-folder
+        "v"    #'mh-show-visit-folder)
+
+  "S" (define-keymap :prefix 'mh-show-sequence-map
+        "'"    #'mh-show-narrow-to-tick
+        "?"    #'mh-prefix-help
+        "d"    #'mh-show-delete-msg-from-seq
+        "k"    #'mh-show-delete-seq
+        "l"    #'mh-show-list-sequences
+        "n"    #'mh-show-narrow-to-seq
+        "p"    #'mh-show-put-msg-in-seq
+        "s"    #'mh-show-msg-is-in-seq
+        "w"    #'mh-show-widen)
+
+  "I" mh-inc-spool-map
+
+  "J" (define-keymap :prefix 'mh-show-junk-map
+        "?"    #'mh-prefix-help
+        "a"    #'mh-show-junk-allowlist
+        "b"    #'mh-show-junk-blocklist
+        "w"    #'mh-show-junk-allowlist)
+
+  "P" (define-keymap :prefix 'mh-show-ps-print-map
+        "?"   #'mh-prefix-help
+        "C"   #'mh-show-ps-print-toggle-color
+        "F"   #'mh-show-ps-print-toggle-faces
+        "f"   #'mh-show-ps-print-msg-file
+        "l"   #'mh-show-print-msg
+        "p"   #'mh-show-ps-print-msg)
+
+  "T" (define-keymap :prefix 'mh-show-thread-map
+        "?"    #'mh-prefix-help
+        "u"    #'mh-show-thread-ancestor
+        "p"    #'mh-show-thread-previous-sibling
+        "n"    #'mh-show-thread-next-sibling
+        "t"    #'mh-show-toggle-threads
+        "d"    #'mh-show-thread-delete
+        "o"    #'mh-show-thread-refile)
+
+  "/" (define-keymap :prefix 'mh-show-limit-map
+        "'"    #'mh-show-narrow-to-tick
+        "?"    #'mh-prefix-help
+        "c"    #'mh-show-narrow-to-cc
+        "g"    #'mh-show-narrow-to-range
+        "m"    #'mh-show-narrow-to-from
+        "s"    #'mh-show-narrow-to-subject
+        "t"    #'mh-show-narrow-to-to
+        "w"    #'mh-show-widen)
+
+  "X" (define-keymap :prefix 'mh-show-extract-map
+        "?"    #'mh-prefix-help
+        "s"    #'mh-show-store-msg
+        "u"    #'mh-show-store-msg)
+
+  "D" (define-keymap :prefix 'mh-show-digest-map
+        "?"    #'mh-prefix-help
+        " "    #'mh-show-page-digest
+        "\177" #'mh-show-page-digest-backwards
+        "b"    #'mh-show-burst-digest)
+
+  "K" (define-keymap :prefix 'mh-show-mime-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-mime-save-parts
+        "e"           #'mh-show-display-with-external-viewer
+        "v"           #'mh-show-toggle-mime-part
+        "o"           #'mh-show-save-mime-part
+        "i"           #'mh-show-inline-mime-part
+        "t"           #'mh-show-toggle-mime-buttons
+        "\t"          #'mh-show-next-button
+        [backtab]     #'mh-show-prev-button
+        "\M-\t"       #'mh-show-prev-button))
 
 
 
@@ -817,9 +817,6 @@ operation."
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-show-mode 'mode-class 'special)
 
-;; Shush compiler.
-(defvar font-lock-auto-fontify)
-
 ;;;###mh-autoload
 (define-derived-mode mh-show-mode text-mode "MH-Show"
   "Major mode for showing messages in MH-E.\\<mh-show-mode-map>
@@ -839,8 +836,6 @@ See also `mh-folder-mode'.
   (mh-do-in-gnu-emacs
    (if (boundp 'tool-bar-map)
        (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :show))
   (set (make-local-variable 'mail-header-separator) mh-mail-header-separator)
   (setq paragraph-start (default-value 'paragraph-start))
   (setq buffer-invisibility-spec '((vanish . t) t))
@@ -858,16 +853,8 @@ See also `mh-folder-mode'.
     (mh-gnus-article-highlight-citation))
    (t
     (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
-  (if (and (featurep 'xemacs)
-           font-lock-auto-fontify)
-      (turn-on-font-lock))
   (when mh-decode-mime-flag
-    (mh-make-local-hook 'kill-buffer-hook)
     (add-hook 'kill-buffer-hook #'mh-mime-cleanup nil t))
-  (mh-do-in-xemacs
-    (easy-menu-add mh-show-sequence-menu)
-    (easy-menu-add mh-show-message-menu)
-    (easy-menu-add mh-show-folder-menu))
   (make-local-variable 'mh-show-folder-buffer)
   (buffer-disable-undo)
   (use-local-map mh-show-mode-map))
diff --git a/lisp/mh-e/mh-speed.el b/lisp/mh-e/mh-speed.el
index 76ef990..a019c28 100644
--- a/lisp/mh-e/mh-speed.el
+++ b/lisp/mh-e/mh-speed.el
@@ -63,13 +63,13 @@
   '("--"
     ["Visit Folder" mh-speed-view
      (with-current-buffer speedbar-buffer
-       (get-text-property (mh-line-beginning-position) 'mh-folder))]
+       (get-text-property (line-beginning-position) 'mh-folder))]
     ["Expand Nested Folders" mh-speed-expand-folder
-     (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
-          (not (get-text-property (mh-line-beginning-position) 'mh-expanded)))]
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (not (get-text-property (line-beginning-position) 'mh-expanded)))]
     ["Contract Nested Folders" mh-speed-contract-folder
-     (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
-          (get-text-property (mh-line-beginning-position) 'mh-expanded))]
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (get-text-property (line-beginning-position) 'mh-expanded))]
     ["Refresh Speedbar" mh-speed-refresh t])
   "Extra menu items for speedbar.")
 
@@ -83,11 +83,11 @@
 (defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
   "Specialized speedbar keymap for MH-E buffers.")
 
-(gnus-define-keys mh-folder-speedbar-key-map
-  "+"           mh-speed-expand-folder
-  "-"           mh-speed-contract-folder
-  "\r"          mh-speed-view
-  "r"           mh-speed-refresh)
+(define-keymap :keymap mh-folder-speedbar-key-map
+  "+"           #'mh-speed-expand-folder
+  "-"           #'mh-speed-contract-folder
+  "\r"          #'mh-speed-view
+  "r"           #'mh-speed-refresh)
 
 (defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
 (defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
@@ -150,7 +150,7 @@ The optional arguments from speedbar are IGNORED."
              (forward-line -1)
              (speedbar-change-expand-button-char ?+)
              (add-text-properties
-              (mh-line-beginning-position) (1+ (line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               '(mh-expanded nil)))
             (t
              (forward-line)
@@ -158,14 +158,14 @@ The optional arguments from speedbar are IGNORED."
              (goto-char point)
              (speedbar-change-expand-button-char ?-)
              (add-text-properties
-              (mh-line-beginning-position) (1+ (line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               '(mh-expanded t)))))))
 
 (defun mh-speed-view (&rest _ignored)
   "Visits the selected folder just as if you had used 
\\<mh-folder-mode-map>\\[mh-visit-folder].
 The optional arguments from speedbar are IGNORED."
   (interactive)
-  (let* ((folder (get-text-property (mh-line-beginning-position) 'mh-folder))
+  (let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
          (range (and (stringp folder)
                      (mh-read-range "Scan" folder t nil nil
                                     mh-interpret-number-as-range-flag))))
@@ -191,9 +191,9 @@ created."
     (forward-line -1)
     (setf (gethash nil mh-speed-folder-map)
           (set-marker (or (gethash nil mh-speed-folder-map) (make-marker))
-                      (1+ (mh-line-beginning-position))))
+                      (1+ (line-beginning-position))))
     (add-text-properties
-     (mh-line-beginning-position) (1+ (line-beginning-position))
+     (line-beginning-position) (1+ (line-beginning-position))
      '(mh-folder nil mh-expanded nil mh-children-p t mh-level 0))
     (mh-speed-stealth-update t)
     (when (> mh-speed-update-interval 0)
@@ -260,12 +260,12 @@ The update is always carried out if FORCE is non-nil."
     (speedbar-with-writable
       (goto-char (gethash folder mh-speed-folder-map (point)))
       (beginning-of-line)
-      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (mh-line-end-position) t)
+      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
           (setq face (mh-speed-bold-face face))
         (setq face (mh-speed-normal-face face)))
       (beginning-of-line)
-      (when (re-search-forward "\\[.\\] " (mh-line-end-position) t)
-        (put-text-property (point) (mh-line-end-position) 'face face)))))
+      (when (re-search-forward "\\[.\\] " (line-end-position) t)
+        (put-text-property (point) (line-end-position) 'face face)))))
 
 (defun mh-speed-normal-face (face)
   "Return normal face for given FACE."
@@ -305,7 +305,7 @@ The function will expand out parent folders of FOLDER if 
needed."
     (while suffix-list
       ;; We always need at least one toggle. We need two if the directory list
       ;; is stale since a folder was added.
-      (when (equal prefix (get-text-property (mh-line-beginning-position)
+      (when (equal prefix (get-text-property (line-beginning-position)
                                              'mh-folder))
         (mh-speed-toggle)
         (unless (get-text-property (point) 'mh-expanded)
@@ -359,9 +359,9 @@ uses."
              (setf (gethash folder-name mh-speed-folder-map)
                    (set-marker (or (gethash folder-name mh-speed-folder-map)
                                    (make-marker))
-                               (1+ (mh-line-beginning-position))))
+                               (1+ (line-beginning-position))))
              (add-text-properties
-              (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               `(mh-folder ,folder-name
                           mh-expanded nil
                           mh-children-p ,(not (not (cdr f)))
@@ -391,7 +391,7 @@ flists is run only for that one folder."
   (interactive (list t))
   (when force
     (when mh-speed-flists-timer
-      (mh-cancel-timer mh-speed-flists-timer)
+      (cancel-timer mh-speed-flists-timer)
       (setq mh-speed-flists-timer nil))
     (when (and (processp mh-speed-flists-process)
                (not (eq (process-status mh-speed-flists-process) 'exit)))
@@ -462,25 +462,25 @@ be handled next."
                           face)
                       (when pos
                         (goto-char pos)
-                        (goto-char (mh-line-beginning-position))
+                        (goto-char (line-beginning-position))
                         (cond
                          ((null (get-text-property (point) 'mh-count))
-                          (goto-char (mh-line-end-position))
+                          (goto-char (line-end-position))
                           (setq face (get-text-property (1- (point)) 'face))
                           (insert (format " (%s/%s)" unseen total))
                           (mh-speed-highlight 'unknown face)
-                          (goto-char (mh-line-beginning-position))
+                          (goto-char (line-beginning-position))
                           (add-text-properties (point) (1+ (point))
                                                `(mh-count (,unseen . ,total))))
                          ((not (equal (get-text-property (point) 'mh-count)
                                       (cons unseen total)))
-                          (goto-char (mh-line-end-position))
+                          (goto-char (line-end-position))
                           (setq face (get-text-property (1- (point)) 'face))
-                          (re-search-backward " " (mh-line-beginning-position) 
t)
-                          (delete-region (point) (mh-line-end-position))
+                          (re-search-backward " " (line-beginning-position) t)
+                          (delete-region (point) (line-end-position))
                           (insert (format " (%s/%s)" unseen total))
                           (mh-speed-highlight 'unknown face)
-                          (goto-char (mh-line-beginning-position))
+                          (goto-char (line-beginning-position))
                           (add-text-properties
                            (point) (1+ (point))
                            `(mh-count (,unseen . ,total))))))))))))
@@ -509,15 +509,15 @@ be handled next."
                              (caar parent-kids)))
                  (setq parent-change ? ))))
         (goto-char parent-position)
-        (when (equal (get-text-property (mh-line-beginning-position) 
'mh-folder)
+        (when (equal (get-text-property (line-beginning-position) 'mh-folder)
                      parent)
-          (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
+          (when (get-text-property (line-beginning-position) 'mh-expanded)
             (mh-speed-toggle))
           (when parent-change
             (speedbar-with-writable
               (mh-speedbar-change-expand-button-char parent-change)
               (add-text-properties
-               (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+               (line-beginning-position) (1+ (line-beginning-position))
                `(mh-children-p ,(equal parent-change ?+)))))
           (mh-speed-highlight mh-speed-last-selected-folder 
'mh-speedbar-folder)
           (setq mh-speed-last-selected-folder nil)
@@ -531,7 +531,7 @@ be handled next."
   "Change the expansion button character to CHAR for the current line."
   (save-excursion
     (beginning-of-line)
-    (if (re-search-forward "\\[.\\]" (mh-line-end-position) t)
+    (if (re-search-forward "\\[.\\]" (line-end-position) t)
         (speedbar-with-writable
           (backward-char 2)
           (delete-char 1)
@@ -562,9 +562,9 @@ The function invalidates the latest ancestor that is 
present."
       (speedbar-with-writable
         (mh-speedbar-change-expand-button-char ?+)
         (add-text-properties
-         (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+         (line-beginning-position) (1+ (line-beginning-position))
          '(mh-children-p t)))
-      (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
+      (when (get-text-property (line-beginning-position) 'mh-expanded)
         (mh-speed-toggle))
       (setq mh-speed-refresh-flag t))))
 
diff --git a/lisp/mh-e/mh-thread.el b/lisp/mh-e/mh-thread.el
index 89b0dbd..a4b4151 100644
--- a/lisp/mh-e/mh-thread.el
+++ b/lisp/mh-e/mh-thread.el
@@ -294,7 +294,7 @@ at the end."
         (while (not (eobp))
           (forward-char address-start-offset)
           (unless (equal (string-match spaces (buffer-substring-no-properties
-                                               (point) (mh-line-end-position)))
+                                               (point) (line-end-position)))
                          0)
             (beginning-of-line)
             (backward-char)
@@ -455,8 +455,8 @@ If optional argument STRING is given then that is assumed 
to be
 the scan line. Otherwise uses the line at point as the scan line
 to parse."
   (let* ((string (or string (buffer-substring-no-properties
-                             (mh-line-beginning-position)
-                             (mh-line-end-position))))
+                             (line-beginning-position)
+                             (line-end-position))))
          (address-start (+ mh-cmd-note mh-scan-field-from-start-offset))
          (body-start (+ mh-cmd-note mh-scan-field-from-end-offset))
          (first-string (substring string 0 address-start)))
@@ -597,20 +597,20 @@ Only information about messages in MSG-LIST are added to 
the tree."
         (while (not (eobp))
           (cl-block process-message
             (let* ((index-line
-                    (prog1 (buffer-substring (point) (mh-line-end-position))
+                    (prog1 (buffer-substring (point) (line-end-position))
                       (forward-line)))
                    (index (string-to-number index-line))
-                   (id (prog1 (buffer-substring (point) (mh-line-end-position))
+                   (id (prog1 (buffer-substring (point) (line-end-position))
                          (forward-line)))
                    (refs (prog1
-                             (buffer-substring (point) (mh-line-end-position))
+                             (buffer-substring (point) (line-end-position))
                            (forward-line)))
                    (in-reply-to (prog1 (buffer-substring (point)
-                                                         
(mh-line-end-position))
+                                                         (line-end-position))
                                   (forward-line)))
                    (subject (prog1
                                 (buffer-substring
-                                 (point) (mh-line-end-position))
+                                 (point) (line-end-position))
                               (forward-line)))
                    (subject-re-p nil))
               (unless (gethash index mh-thread-scan-line-map)
diff --git a/lisp/mh-e/mh-tool-bar.el b/lisp/mh-e/mh-tool-bar.el
index 94aa8dd..805408c 100644
--- a/lisp/mh-e/mh-tool-bar.el
+++ b/lisp/mh-e/mh-tool-bar.el
@@ -29,8 +29,6 @@
 (require 'mh-e)
 (mh-do-in-gnu-emacs
   (require 'tool-bar))
-(mh-do-in-xemacs
-  (require 'toolbar))
 
 ;;; Tool Bar Commands
 
@@ -79,9 +77,6 @@ When INCLUDE-FLAG is non-nil, include message body being 
replied to."
 
 ;;; Tool Bar Creation
 
-;; Shush compiler.
-(defvar image-load-path)
-
 (defmacro mh-tool-bar-define (defaults &rest buttons)
   "Define a tool bar for MH-E.
 DEFAULTS is the list of buttons that are present by default. It
@@ -145,8 +140,6 @@ where,
       (let* ((name (nth 0 button))
              (name-str (symbol-name name))
              (icon (nth 2 button))
-             (xemacs-icon (mh-do-in-xemacs
-                            `(cdr (assoc (quote ,(intern icon)) 
mh-xemacs-icon-map))))
              (full-doc (nth 3 button))
              (doc (if (string-match "\\(.*\\)\n" full-doc)
                       (match-string 1 full-doc)
@@ -186,7 +179,7 @@ where,
                                  (t 'folder-buttons)))
                  (docs (cond ((eq mbuttons 'letter-buttons) 'letter-docs)
                              ((eq mbuttons 'folder-buttons) 'folder-docs))))
-            (add-to-list vector-list `(vector ,xemacs-icon ',function t 
,full-doc))
+            (add-to-list vector-list `(vector nil ',function t ,full-doc))
             (add-to-list
              setter `(when (member ',name ,list)
                        (mh-funcall-if-exists
@@ -220,8 +213,8 @@ where,
          ;; Tool bar initialization functions
          (defun mh-tool-bar-folder-buttons-init ()
            (when (mh-buffer-exists-p 'mh-folder-mode)
-             (let* ((load-path (mh-image-load-path-for-library "mh-e"
-                                                               "mh-logo.xpm"))
+             (let* ((load-path (image-load-path-for-library "mh-e"
+                                                            "mh-logo.xpm"))
                     (image-load-path (cons (car load-path)
                                            (when (boundp 'image-load-path)
                                              image-load-path))))
@@ -243,8 +236,8 @@ where,
                        tool-bar-map)))))
          (defun mh-tool-bar-letter-buttons-init ()
            (when (mh-buffer-exists-p 'mh-letter-mode)
-             (let* ((load-path (mh-image-load-path-for-library "mh-e"
-                                                               "mh-logo.xpm"))
+             (let* ((load-path (image-load-path-for-library "mh-e"
+                                                            "mh-logo.xpm"))
                     (image-load-path (cons (car load-path)
                                            (when (boundp 'image-load-path)
                                              image-load-path))))
@@ -282,72 +275,6 @@ Use SEQUENCE-MAP if display is limited; DEFAULT-MAP 
otherwise."
            (mh-tool-bar-letter-buttons-init)
            (mh-tool-bar-update 'mh-letter-mode mh-letter-tool-bar-map
                                mh-letter-tool-bar-map)))
-       ;; XEmacs specific code
-       (mh-do-in-xemacs
-         (defvar mh-tool-bar-folder-vector-map
-           (list ,@(cl-loop for button in folder-buttons
-                            for vector in folder-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-show-vector-map
-           (list ,@(cl-loop for button in show-buttons
-                            for vector in show-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-letter-vector-map
-           (list ,@(cl-loop for button in letter-buttons
-                            for vector in letter-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-folder-buttons)
-         (defvar mh-tool-bar-show-buttons)
-         (defvar mh-tool-bar-letter-buttons)
-         ;; Custom setter functions
-         (defun mh-tool-bar-letter-buttons-set (symbol value)
-           (set-default symbol value)
-           (when mh-xemacs-has-tool-bar-flag
-             (setq mh-tool-bar-letter-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-letter-vector-map))))))
-         (defun mh-tool-bar-folder-buttons-set (symbol value)
-           (set-default symbol value)
-           (when mh-xemacs-has-tool-bar-flag
-             (setq mh-tool-bar-folder-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-folder-vector-map))))
-             (setq mh-tool-bar-show-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-show-vector-map))))))
-         (defun mh-tool-bar-init (mode)
-           "Install tool bar in MODE."
-           (when mh-xemacs-use-tool-bar-flag
-             (let ((tool-bar (cond ((eq mode :folder)
-                                    mh-tool-bar-folder-buttons)
-                                   ((eq mode :letter)
-                                    mh-tool-bar-letter-buttons)
-                                   ((eq mode :show)
-                                    mh-tool-bar-show-buttons)))
-                   (height 37)
-                   (width 40)
-                   (buffer (current-buffer)))
-               (cond
-                ((eq mh-xemacs-tool-bar-position 'top)
-                 (set-specifier top-toolbar tool-bar buffer)
-                 (set-specifier top-toolbar-visible-p t)
-                 (set-specifier top-toolbar-height height))
-                ((eq mh-xemacs-tool-bar-position 'bottom)
-                 (set-specifier bottom-toolbar tool-bar buffer)
-                 (set-specifier bottom-toolbar-visible-p t)
-                 (set-specifier bottom-toolbar-height height))
-                ((eq mh-xemacs-tool-bar-position 'left)
-                 (set-specifier left-toolbar tool-bar buffer)
-                 (set-specifier left-toolbar-visible-p t)
-                 (set-specifier left-toolbar-width width))
-                ((eq mh-xemacs-tool-bar-position 'right)
-                 (set-specifier right-toolbar tool-bar buffer)
-                 (set-specifier right-toolbar-visible-p t)
-                 (set-specifier right-toolbar-width width))
-                (t (set-specifier default-toolbar tool-bar buffer)))))))
        ;; Declare customizable tool bars
        (custom-declare-variable
         'mh-tool-bar-folder-buttons
@@ -372,7 +299,6 @@ Use SEQUENCE-MAP if display is limited; DEFAULT-MAP 
otherwise."
         ;;:package-version '(MH-E "7.1")
         ))))
 
-;; The icon names are duplicated in the Makefile and mh-xemacs.el.
 (mh-tool-bar-define
  ((:folder mh-inc-folder mh-mime-save-parts
            mh-previous-undeleted-msg mh-page-msg
diff --git a/lisp/mh-e/mh-utils.el b/lisp/mh-e/mh-utils.el
index bbce170..93bc7f8 100644
--- a/lisp/mh-e/mh-utils.el
+++ b/lisp/mh-e/mh-utils.el
@@ -52,7 +52,7 @@ used in lieu of `search' in the CL package."
   (let ((syntax-table (syntax-table)))
     (unwind-protect
         (save-excursion
-          (mh-mail-abbrev-make-syntax-table)
+          (mail-abbrev-make-syntax-table)
           (set-syntax-table mail-abbrev-syntax-table)
           (backward-word n)
           (point))
@@ -61,9 +61,9 @@ used in lieu of `search' in the CL package."
 ;;;###mh-autoload
 (defun mh-colors-available-p ()
   "Check if colors are available in the Emacs being used."
-  (or (featurep 'xemacs)
-      (let ((color-cells (mh-display-color-cells)))
-        (and (numberp color-cells) (>= color-cells 8)))))
+  ;; 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 ()
@@ -102,7 +102,7 @@ PICK-EXPR is a list of strings. Return nil if PICK-EXPR is 
nil."
                  (not (string-equal string "")))
         (cl-loop for i from 0 to (1- (length mh-pick-regexp-chars)) do
                  (let ((s (string ?\\ (aref mh-pick-regexp-chars i))))
-                   (setq string (mh-replace-regexp-in-string s s string t t))))
+                   (setq string (replace-regexp-in-string s s string t t))))
         (setq quoted-pick-expr (append quoted-pick-expr (list string)))))
     quoted-pick-expr))
 
@@ -121,14 +121,11 @@ Ignores case when searching for OLD."
 
 (defvar mh-logo-cache nil)
 
-;; Shush compiler.
-(defvar image-load-path)
-
 ;;;###mh-autoload
 (defun mh-logo-display ()
   "Modify mode line to display MH-E logo."
   (mh-do-in-gnu-emacs
-    (let* ((load-path (mh-image-load-path-for-library "mh-e" "mh-logo.xpm"))
+    (let* ((load-path (image-load-path-for-library "mh-e" "mh-logo.xpm"))
            (image-load-path (cons (car load-path)
                                   (when (boundp 'image-load-path)
                                     image-load-path))))
@@ -139,14 +136,7 @@ Ignores case when searching for OLD."
                             (mh-funcall-if-exists
                              find-image '((:type xpm :ascent center
                                                  :file "mh-logo.xpm"))))))
-       (car mode-line-buffer-identification))))
-  (mh-do-in-xemacs
-    (setq modeline-buffer-identification
-          (list
-           (if mh-modeline-glyph
-               (cons modeline-buffer-id-left-extent mh-modeline-glyph)
-             (cons modeline-buffer-id-left-extent "XEmacs%N:"))
-           (cons modeline-buffer-id-right-extent " %17b")))))
+       (car mode-line-buffer-identification)))))
 
 
 
@@ -509,8 +499,8 @@ they will not be returned."
     ;; folder is specified, ensure it is nil to avoid adding the
     ;; folder to the folder-list and adding a slash to it.
     (when folder
-      (setq folder (mh-replace-regexp-in-string "^\\+" "" folder))
-      (setq folder (mh-replace-regexp-in-string "/+$" "" folder))
+      (setq folder (replace-regexp-in-string "^\\+" "" folder))
+      (setq folder (replace-regexp-in-string "/+$" "" folder))
       (if (equal folder "")
           (setq folder nil)))
     ;; Add provided folder to list, unless all folders are asked for.
@@ -573,10 +563,10 @@ Expects FOLDER to have already been normalized with
       (apply #'call-process arg-list)
       (goto-char (point-min))
       (while (not (and (eolp) (bolp)))
-        (goto-char (mh-line-end-position))
-        (let ((start-pos (mh-line-beginning-position))
+        (goto-char (line-end-position))
+        (let ((start-pos (line-beginning-position))
               (has-pos (search-backward " has "
-                                        (mh-line-beginning-position) t)))
+                                        (line-beginning-position) t)))
           (when (integerp has-pos)
             (while (equal (char-after has-pos) ? )
               (cl-decf has-pos))
@@ -591,7 +581,7 @@ Expects FOLDER to have already been normalized with
                   (setq name (substring name 0 (1- (length name)))))
                 (push
                  (cons name
-                       (search-forward "(others)" (mh-line-end-position) t))
+                       (search-forward "(others)" (line-end-position) t))
                  results))))
           (forward-line 1))))
     (setq results (nreverse results))
@@ -922,9 +912,6 @@ Handle RFC 822 (or later) continuation lines."
   (let ((map (make-sparse-keymap)))
     (mh-do-in-gnu-emacs
       (define-key map [mouse-2] 
#'mh-letter-toggle-header-field-display-button))
-    (mh-do-in-xemacs
-      (define-key map '(button2)
-        #'mh-letter-toggle-header-field-display-button))
     map))
 
 ;;;###mh-autoload
@@ -958,9 +945,9 @@ is hidden, if positive then the field is displayed."
                      (and (numberp arg)
                           (>= arg 0))
                      (and (eq arg 'long)
-                          (> (mh-line-beginning-position 5) end)))
+                          (> (line-beginning-position 5) end)))
                  (remove-text-properties begin end '(invisible nil))
-                 (search-forward ":" (mh-line-end-position) t)
+                 (search-forward ":" (line-end-position) t)
                  (mh-letter-skip-leading-whitespace-in-header-field))
                 ;; XXX Redesign to make usable by user. Perhaps use a positive
                 ;; numeric prefix to make that many lines visible.
diff --git a/lisp/mh-e/mh-xface.el b/lisp/mh-e/mh-xface.el
index 58177c1..5983353 100644
--- a/lisp/mh-e/mh-xface.el
+++ b/lisp/mh-e/mh-xface.el
@@ -31,10 +31,7 @@
 (autoload 'message-fetch-field "message")
 
 (defvar mh-show-xface-function
-  (cond ((and (featurep 'xemacs) (locate-library "x-face") (not (featurep 
'xface)))
-         (load "x-face" t t)
-         #'mh-face-display-function)
-        ((>= emacs-major-version 21)
+  (cond ((>= emacs-major-version 21)
          #'mh-face-display-function)
         (t #'ignore))
   "Determine at run time what function should be called to display X-Face.")
@@ -77,7 +74,6 @@ in this order is used."
       (when type
         (goto-char (point-min))
         (when (re-search-forward "^from:" (point-max) t)
-          ;; GNU Emacs
           (mh-do-in-gnu-emacs
             (if (eq type 'url)
                 (mh-x-image-url-display url)
@@ -85,39 +81,10 @@ in this order is used."
                insert-image (create-image
                              raw type t
                              :foreground
-                             (mh-face-foreground 'mh-show-xface nil t)
+                             (face-foreground 'mh-show-xface nil t)
                              :background
-                             (mh-face-background 'mh-show-xface nil t))
-               " ")))
-          ;; XEmacs
-          (mh-do-in-xemacs
-            (cond
-             ((eq type 'url)
-              (mh-x-image-url-display url))
-             ((eq type 'png)
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector 'png ':data (mh-face-to-png face))))))
-             ;; Try internal xface support if available...
-             ((and (eq type 'pbm) (featurep 'xface))
-              (set-glyph-face
-               (set-extent-begin-glyph
-                (make-extent (point) (point))
-                (make-glyph (vector 'xface ':data (concat "X-Face: " x-face))))
-               'mh-show-xface))
-             ;; Otherwise try external support with x-face...
-             ((and (eq type 'pbm)
-                   (fboundp 'x-face-xmas-wl-display-x-face)
-                   (fboundp 'executable-find) (executable-find "uncompface"))
-              (mh-funcall-if-exists x-face-xmas-wl-display-x-face))
-             ;; Picon display
-             ((and raw (member type '(xpm xbm gif)))
-              (when (featurep type)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector type ':data raw))))))
-            (when raw (insert " "))))))))
+                             (face-background 'mh-show-xface nil t))
+               " "))))))))
 
 (defun mh-face-to-png (data)
   "Convert base64 encoded DATA to png image."
@@ -178,8 +145,7 @@ The directories are searched for in the order they appear 
in the list.")
   (cl-loop for type in '(xpm xbm gif)
            when (or (mh-do-in-gnu-emacs
                      (ignore-errors
-                       (mh-funcall-if-exists image-type-available-p type)))
-                    (mh-do-in-xemacs (featurep type)))
+                       (image-type-available-p type))))
            collect type))
 
 (autoload 'message-tokenize-header "sendmail")
@@ -357,14 +323,14 @@ This is only done if `mh-x-image-cache-directory' is nil."
 (defun mh-x-image-url-cache-canonicalize (url)
   "Canonicalize URL.
 Replace the ?/ character with a ?! character and append .png.
-Also replaces special characters with `mh-url-hexify-string'
+Also replaces special characters with `url-hexify-string'
 since not all characters, such as :, are valid within Windows
 filenames.  In addition, replaces * with %2a. See URL
 
`https://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/iitemnamelimits/GetValidCharacters.asp'."
   (format "%s/%s.png" mh-x-image-cache-directory
-          (mh-replace-regexp-in-string
+          (replace-regexp-in-string
            "\\*" "%2a"
-           (mh-url-hexify-string
+           (url-hexify-string
             (with-temp-buffer
               (insert url)
               (mh-replace-string "/" "!")
@@ -405,15 +371,7 @@ filenames.  In addition, replaces * with %2a. See URL
                      (eq marker mh-x-image-marker))
             (goto-char marker)
             (mh-do-in-gnu-emacs
-              (mh-funcall-if-exists insert-image (create-image image 'png)))
-            (mh-do-in-xemacs
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph
-                  (vector 'png ':data (with-temp-buffer
-                                        (insert-file-contents-literally image)
-                                        (buffer-string))))))))
+              (insert-image (create-image image 'png))))
         (set-buffer-modified-p buffer-modified-flag)))))
 
 (defun mh-x-image-url-fetch-image (url cache-file marker sentinel)
@@ -423,8 +381,7 @@ be displayed in a buffer and position specified by MARKER. 
The
 actual display is carried out by the SENTINEL function."
   (if mh-wget-executable
       (let ((buffer (generate-new-buffer mh-temp-fetch-buffer))
-            (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
-                          (expand-file-name (make-temp-name "~/mhe-fetch")))))
+            (filename (make-temp-file "mhe-fetch")))
         (with-current-buffer buffer
           (set (make-local-variable 'mh-x-image-url-cache-file) cache-file)
           (set (make-local-variable 'mh-x-image-marker) marker)
diff --git a/lisp/obsolete/crisp.el b/lisp/obsolete/crisp.el
index 69bf3ed..ccf9aaa 100644
--- a/lisp/obsolete/crisp.el
+++ b/lisp/obsolete/crisp.el
@@ -231,27 +231,13 @@ does not load the scroll-all package."
 
 ;; The cut and paste routines are different between XEmacs and Emacs
 ;; so we need to set up aliases for the functions.
-
-(defalias 'crisp-set-clipboard
-  (if (fboundp 'clipboard-kill-ring-save)
-      'clipboard-kill-ring-save
-    'copy-primary-selection))
-
-(defalias 'crisp-kill-region
-  (if (fboundp 'clipboard-kill-region)
-      'clipboard-kill-region
-    'kill-primary-selection))
-
-(defalias 'crisp-yank-clipboard
-  (if (fboundp 'clipboard-yank)
-      'clipboard-yank
-    'yank-clipboard-selection))
+(defalias 'crisp-set-clipboard 'clipboard-kill-ring-save)
+(defalias 'crisp-kill-region 'clipboard-kill-region)
+(defalias 'crisp-yank-clipboard 'clipboard-yank)
 
 (defun crisp-region-active ()
   "Compatibility function to test for an active region."
-  (if (featurep 'xemacs)
-      zmacs-region-active-p
-    mark-active))
+  mark-active)
 
 (defun crisp-version (&optional arg)
   "Version number of the CRiSP emulator package.
diff --git a/lisp/obsolete/eudcb-ph.el b/lisp/obsolete/eudcb-ph.el
index 187879c..51a6780 100644
--- a/lisp/obsolete/eudcb-ph.el
+++ b/lisp/obsolete/eudcb-ph.el
@@ -176,9 +176,7 @@ SERVER is either a string naming the server or a list (NAME 
PORT)."
       (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" 
host)))
       (with-current-buffer eudc-ph-process-buffer
        (erase-buffer)
-       (setq eudc-ph-read-point (point))
-       (and (featurep 'xemacs) (featurep 'mule)
-            (set-buffer-file-coding-system 'binary t)))
+        (setq eudc-ph-read-point (point)))
       (setq process (open-network-stream "ph" eudc-ph-process-buffer host 
port))
       (if (null process)
          (throw 'done nil))
diff --git a/lisp/obsolete/fast-lock.el b/lisp/obsolete/fast-lock.el
index 960233d..1dee712 100644
--- a/lisp/obsolete/fast-lock.el
+++ b/lisp/obsolete/fast-lock.el
@@ -283,10 +283,7 @@ If a number, only buffers greater than this size have 
processing messages."
                 (other :tag "always" t)
                 (integer :tag "size")))
 
-(defvar fast-lock-save-faces
-  (when (featurep 'xemacs)
-    ;; XEmacs uses extents for everything, so we have to pick the right ones.
-    font-lock-face-list)
+(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.")
 
@@ -707,35 +704,7 @@ See `fast-lock-get-face-properties'."
          (while regions
            (add-text-properties (nth 0 regions) (nth 1 regions) plist)
            (setq regions (nthcdr 2 regions))))))))
-
-;; Functions for XEmacs:
-
-(unless (boundp 'font-lock-syntactic-keywords)
-  (defvar font-lock-syntactic-keywords nil))
-
-(unless (boundp 'font-lock-inhibit-thing-lock)
-  (defvar font-lock-inhibit-thing-lock nil))
-
-(unless (fboundp 'font-lock-compile-keywords)
-  (defalias 'font-lock-compile-keywords #'identity))
-
-(unless (fboundp 'font-lock-eval-keywords)
-  (defun font-lock-eval-keywords (keywords)
-    (if (symbolp keywords)
-       (font-lock-eval-keywords (if (fboundp keywords)
-                                    (funcall keywords)
-                                  (eval keywords t)))
-      keywords)))
-
-(unless (fboundp 'font-lock-value-in-major-mode)
-  (defun font-lock-value-in-major-mode (alist)
-    (if (consp alist)
-       (cdr (or (assq major-mode alist) (assq t alist)))
-      alist)))
-
-(unless (fboundp 'current-message)
-  (defun current-message ()
-    ""))
+
 
 ;; Install ourselves:
 
diff --git a/lisp/obsolete/iswitchb.el b/lisp/obsolete/iswitchb.el
index a630baf..807f548 100644
--- a/lisp/obsolete/iswitchb.el
+++ b/lisp/obsolete/iswitchb.el
@@ -977,17 +977,7 @@ Return the modified list with the last element prepended 
to it."
          (set-buffer buf))
 
       (with-output-to-temp-buffer temp-buf
-       (if (featurep 'xemacs)
-
-           ;; XEmacs extents are put on by default, doesn't seem to be
-           ;; any way of switching them off.
-           (display-completion-list (or iswitchb-matches iswitchb-buflist)
-                                    :help-string "iswitchb "
-                                    :activate-callback
-                                    (lambda (_x _y _z)
-                                      (message "doesn't work yet, sorry!")))
-         ;; else running Emacs
-         (display-completion-list (or iswitchb-matches iswitchb-buflist))))
+        (display-completion-list (or iswitchb-matches iswitchb-buflist)))
       (setq iswitchb-common-match-inserted nil))))
 
 ;;; KILL CURRENT BUFFER
@@ -1326,9 +1316,7 @@ This is an example function which can be hooked on to
   "Return non-nil if we should ignore case when matching.
 See the variable `iswitchb-case' for details."
   (if iswitchb-case
-      (if (featurep 'xemacs)
-         (isearch-no-upper-case-p iswitchb-text)
-       (isearch-no-upper-case-p iswitchb-text t))))
+      (isearch-no-upper-case-p iswitchb-text t)))
 
 ;;;###autoload
 (define-minor-mode iswitchb-mode
diff --git a/lisp/obsolete/otodo-mode.el b/lisp/obsolete/otodo-mode.el
index 47f5089..a71d2b8 100644
--- a/lisp/obsolete/otodo-mode.el
+++ b/lisp/obsolete/otodo-mode.el
@@ -908,8 +908,7 @@ If INCLUDE-SEP is non-nil, return point after the 
separator."
 ;;;###autoload
 (define-derived-mode todo-mode nil "TODO"
   "Major mode for editing TODO lists."
-  (when (featurep 'xemacs)
-    (easy-menu-add todo-menu)))
+  nil)
 
 (with-suppressed-warnings ((lexical date entry))
   (defvar date)
diff --git a/lisp/obsolete/pgg-parse.el b/lisp/obsolete/pgg-parse.el
index 2c76365..3e4c216 100644
--- a/lisp/obsolete/pgg-parse.el
+++ b/lisp/obsolete/pgg-parse.el
@@ -496,8 +496,7 @@
 (defun pgg-parse-armor (string)
   (with-temp-buffer
     (buffer-disable-undo)
-    (unless (featurep 'xemacs)
-      (set-buffer-multibyte nil))
+    (set-buffer-multibyte nil)
     (insert string)
     (pgg-decode-armor-region (point-min)(point))))
 
diff --git a/lisp/obsolete/pgg.el b/lisp/obsolete/pgg.el
index 5ed5993..127e1dc 100644
--- a/lisp/obsolete/pgg.el
+++ b/lisp/obsolete/pgg.el
@@ -376,8 +376,7 @@ signer's public key from `pgg-default-keyserver-address'."
          (if (null signature) nil
            (with-temp-buffer
              (buffer-disable-undo)
-             (unless (featurep 'xemacs)
-               (set-buffer-multibyte nil))
+              (set-buffer-multibyte nil)
              (insert-file-contents signature)
              (cdr (assq 2 (pgg-decode-armor-region
                            (point-min)(point-max)))))))
diff --git a/lisp/obsolete/tpu-edt.el b/lisp/obsolete/tpu-edt.el
index e0e89c3..b59fb8c 100644
--- a/lisp/obsolete/tpu-edt.el
+++ b/lisp/obsolete/tpu-edt.el
@@ -650,12 +650,8 @@ GOLD is the ASCII 7-bit escape sequence <ESC>OP.")
   (setq tpu-mark-flag (if transient-mark-mode "" (if (tpu-mark) " @" "  ")))
   (force-mode-line-update))
 
-(cond ((featurep 'xemacs)
-       (add-hook 'zmacs-deactivate-region-hook 'tpu-update-mode-line)
-       (add-hook 'zmacs-activate-region-hook 'tpu-update-mode-line))
-      (t
-       (add-hook 'activate-mark-hook 'tpu-update-mode-line)
-       (add-hook 'deactivate-mark-hook 'tpu-update-mode-line)))
+(add-hook 'activate-mark-hook 'tpu-update-mode-line)
+(add-hook 'deactivate-mark-hook 'tpu-update-mode-line)
 
 
 ;;;
@@ -727,15 +723,13 @@ Otherwise sets the tpu-match markers to nil and returns 
nil."
   "TPU-edt version of the mark function.
 Return the appropriate value of the mark for the current
 version of Emacs."
-  (cond ((featurep 'xemacs) (mark (not zmacs-regions)))
-       (t (and mark-active (mark (not transient-mark-mode))))))
+  (and mark-active (mark (not transient-mark-mode))))
 
 (defun tpu-set-mark (pos)
   "TPU-edt version of the `set-mark' function.
 Sets the mark at POS and activates the region according to the
 current version of Emacs."
-  (set-mark pos)
-  (when (featurep 'xemacs) (when pos (zmacs-activate-region))))
+  (set-mark pos))
 
 (defun tpu-string-prompt (prompt history-symbol)
   "Read a string with PROMPT."
@@ -2306,17 +2300,14 @@ Accepts a prefix argument for the number of 
tpu-pan-columns to scroll."
 ;;;
 (defun tpu-load-xkeys (file)
   "Load the TPU-edt X-windows key definitions FILE.
-If FILE is nil, try to load a default file.  The default file names are
-`~/.tpu-lucid-keys' for XEmacs, and `~/.tpu-keys' for Emacs."
+If FILE is nil, try to load a default file.  The default file name is
+`~/.tpu-keys'."
   (interactive "fX key definition file: ")
   (cond (file
         (setq file (expand-file-name file)))
        (tpu-xkeys-file
         (setq file (expand-file-name tpu-xkeys-file)))
-       ((featurep 'xemacs)
-        (setq file (convert-standard-filename
-                    (expand-file-name "~/.tpu-lucid-keys"))))
-       (t
+        (t
         (setq file (convert-standard-filename
                     (expand-file-name "~/.tpu-keys")))
         (and (not (file-exists-p file))
diff --git a/lisp/obsolete/tpu-mapper.el b/lisp/obsolete/tpu-mapper.el
index 5ae0a65..02ba363 100644
--- a/lisp/obsolete/tpu-mapper.el
+++ b/lisp/obsolete/tpu-mapper.el
@@ -46,24 +46,14 @@
 ;;;
 (defun tpu-map-key (ident descrip func gold-func)
   (interactive)
-  (if (featurep 'xemacs)
-      (progn
-       (setq tpu-key-seq (read-key-sequence
-                           (format "Press %s%s: " ident descrip))
-              tpu-key (format "[%s]" (event-key (aref tpu-key-seq 0))))
-       (unless (equal tpu-key tpu-return)
-          (set-buffer "Keys")
-          (insert (format"(global-set-key %s %s)\n" tpu-key func))
-          (set-buffer "Gold-Keys")
-          (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key 
gold-func))))
-    (message "Press %s%s: " ident descrip)
-    (setq tpu-key-seq (read-event)
-          tpu-key (format "[%s]" tpu-key-seq))
-    (unless (equal tpu-key tpu-return)
-      (set-buffer "Keys")
-      (insert (format"(define-key tpu-global-map %s %s)\n" tpu-key func))
-      (set-buffer "Gold-Keys")
-      (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key gold-func))))
+  (message "Press %s%s: " ident descrip)
+  (setq tpu-key-seq (read-event)
+        tpu-key (format "[%s]" tpu-key-seq))
+  (unless (equal tpu-key tpu-return)
+    (set-buffer "Keys")
+    (insert (format"(define-key tpu-global-map %s %s)\n" tpu-key func))
+    (set-buffer "Gold-Keys")
+    (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key gold-func)))
   (set-buffer "Directions")
   tpu-key)
 
@@ -103,8 +93,7 @@ your local X guru can try to figure out why the key is being 
ignored."
 
   ;; Make sure the window is big enough to display the instructions
 
-  (if (featurep 'xemacs) (set-screen-size (selected-screen) 80 36)
-    (set-frame-size (selected-frame) 80 36))
+  (set-frame-size (selected-frame) 80 36)
 
   ;; Create buffers - Directions, Keys, Gold-Keys
 
@@ -162,14 +151,9 @@ your local X guru can try to figure out why the key is 
being ignored."
 
   ;; Save <CR> for future reference
 
-  (cond
-   ((featurep 'xemacs)
-    (setq tpu-return-seq (read-key-sequence "Hit carriage-return <CR> to 
continue "))
-    (setq tpu-return (concat "[" (format "%s" (event-key (aref tpu-return-seq 
0))) "]")))
-   (t
-    (message "Hit carriage-return <CR> to continue ")
-    (setq tpu-return-seq (read-event))
-    (setq tpu-return (concat "[" (format "%s" tpu-return-seq) "]"))))
+  (message "Hit carriage-return <CR> to continue ")
+  (setq tpu-return-seq (read-event))
+  (setq tpu-return (concat "[" (format "%s" tpu-return-seq) "]"))
 
   ;; Build the keymap file
 
@@ -308,24 +292,14 @@ your local X guru can try to figure out why the key is 
being ignored."
 ;;
 ")
 
-  (cond ((featurep 'xemacs)
-        (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter-seq))
-        (insert (format "(setq tpu-help-return \"%s\")\n" tpu-return-seq))
-        (insert "(setq tpu-help-N \"[#<keypress-event N>]\")\n")
-        (insert "(setq tpu-help-n \"[#<keypress-event n>]\")\n")
-        (insert "(setq tpu-help-P \"[#<keypress-event P>]\")\n")
-        (insert "(setq tpu-help-p \"[#<keypress-event p>]\")\n"))
-       (t
-        (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter))))
+  (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter))
 
   (append-to-buffer "Keys" 1 (point))
   (set-buffer "Keys")
 
   ;; Save the key mapping program
 
-  (let ((file
-        (convert-standard-filename
-         (if (featurep 'xemacs) "~/.tpu-lucid-keys" "~/.tpu-keys"))))
+  (let ((file (convert-standard-filename "~/.tpu-keys")))
     (set-visited-file-name
      (read-file-name (format "Save key mapping to file (default %s): " file) 
"" file)))
   (save-buffer)
diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el
index fd014a3..c6327c1 100644
--- a/lisp/progmodes/bug-reference.el
+++ b/lisp/progmodes/bug-reference.el
@@ -269,7 +269,7 @@ via the internet it might also be http.")
 ;; pull/17 page if 17 is a PR.  Explicit user/project#17 links to
 ;; possibly different projects are also supported.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql github)) protocol)
+  (host-domain (_forge-type (eql 'github)) protocol)
   `(,(concat "[/@]" host-domain "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
     ,(lambda (groups)
@@ -284,7 +284,7 @@ via the internet it might also be http.")
 ;; namespace/project#18 or namespace/project!17 references to possibly
 ;; different projects are also supported.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql gitlab)) protocol)
+  (host-domain (_forge-type (eql 'gitlab)) protocol)
   `(,(concat "[/@]" (regexp-quote host-domain)
              "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\([#!]\\)\\([0-9]+\\)\\)\\>"
@@ -301,7 +301,7 @@ via the internet it might also be http.")
 
 ;; Gitea: The systematics is exactly as for Github projects.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql gitea)) protocol)
+  (host-domain (_forge-type (eql 'gitea)) protocol)
   `(,(concat "[/@]" (regexp-quote host-domain)
              "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
@@ -322,7 +322,7 @@ via the internet it might also be http.")
 ;; repo without tracker, or a repo with a tracker using a different
 ;; name, etc.  So we can only try to make a good guess.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql sourcehut)) protocol)
+  (host-domain (_forge-type (eql 'sourcehut)) protocol)
   `(,(concat "[/@]\\(?:git\\|hg\\)." (regexp-quote host-domain)
              "[/:]\\(~[.A-Za-z0-9_/-]+\\)")
     "\\(\\(~[.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index 454279c..f55115e 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -963,12 +963,7 @@ If set to \"\\n\", each line in the history file will be 
interpreted as
 one command.  Multi-line commands are split into several commands when
 the input ring is initialized from a history file.
 
-This variable used to initialize `comint-input-ring-separator'.
-`comint-input-ring-separator' is part of Emacs 21; if your Emacs
-does not have it, setting `sql-input-ring-separator' will have no
-effect.  In that case multiline commands will be split into several
-commands when the input history is read, as if you had set
-`sql-input-ring-separator' to \"\\n\"."
+This variable used to initialize `comint-input-ring-separator'."
   :type 'string)
 
 ;; The usual hooks
@@ -1357,8 +1352,6 @@ specified, it's `sql-product' or `sql-connection' must 
match."
 (defvar sql-interactive-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map comint-mode-map)
-    (if (fboundp 'set-keymap-name)
-       (set-keymap-name map 'sql-interactive-mode-map)); XEmacs
     (define-key map (kbd "C-j") 'sql-accumulate-and-indent)
     (define-key map (kbd "C-c C-w") 'sql-copy-column)
     (define-key map (kbd "O") 'sql-magic-go)
@@ -2832,16 +2825,6 @@ configured."
       (font-lock-mode-internal nil)
       (font-lock-mode-internal t))
 
-    (add-hook 'font-lock-mode-hook
-              (lambda ()
-                  ;; Provide defaults for new font-lock faces.
-                  (defvar font-lock-builtin-face
-                    (if (boundp 'font-lock-preprocessor-face)
-                        font-lock-preprocessor-face
-                      font-lock-keyword-face))
-                  (defvar font-lock-doc-face font-lock-string-face))
-             nil t)
-
     ;; Setup imenu; it needs the same syntax-alist.
     (when imenu
       (setq imenu-syntax-alist syntax-alist))))
@@ -4175,10 +4158,6 @@ must tell Emacs.  Here's how to do that in your init 
file:
            (modify-syntax-entry ?\\\\ \"\\\\\" sql-mode-syntax-table)))"
   :abbrev-table sql-mode-abbrev-table
 
-  (when (and (featurep 'xemacs)
-             sql-mode-menu)
-      (easy-menu-add sql-mode-menu))
-
   ;; (smie-setup sql-smie-grammar #'sql-smie-rules)
   (setq-local comment-start "--")
   ;; Make each buffer in sql-mode remember the "current" SQLi buffer.
@@ -4301,9 +4280,6 @@ you entered, right above the output it created.
   (setq mode-name
         (concat "SQLi[" (or (sql-get-product-feature sql-product :name)
                             (symbol-name sql-product)) "]"))
-  (when (and (featurep 'xemacs)
-             sql-interactive-mode-menu)
-    (easy-menu-add sql-interactive-mode-menu))
 
   ;; Note that making KEYWORDS-ONLY nil will cause havoc if you try
   ;; SELECT 'x' FROM DUAL with SQL*Plus, because the title of the column
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index f4716fe..52a4e0c 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-2021 Free Software Foundation, Inc.
-;; Version: 1.2.2
+;; Version: 1.3.0
 ;; Package-Requires: ((emacs "26.1"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -74,6 +74,20 @@
 (require 'ring)
 (require 'project)
 
+(eval-and-compile
+  (when (version< emacs-version "28")
+    ;; etags.el in Emacs 26 and 27 uses EIEIO, and its location type
+    ;; inherits from `xref-location'.
+    (require 'eieio)
+
+    ;; Suppressing byte-compilation warnings (in Emacs 28+) about
+    ;; `defclass' not being defined, which happens because the
+    ;; `require' statement above is not evaluated either.
+    ;; FIXME: Use `with-suppressed-warnings' when we stop supporting Emacs 26.
+    (with-no-warnings
+      (defclass xref-location () ()
+        :documentation "(Obsolete) location represents a position in a file or 
buffer."))))
+
 (defgroup xref nil "Cross-referencing commands."
   :version "25.1"
   :group 'tools)
@@ -942,13 +956,11 @@ GROUP is a string for decoration purposes and XREF is an
 `xref-item' object."
   (require 'compile) ; For the compilation faces.
   (cl-loop for (group . xrefs) in xref-alist
-           for max-line-width =
-           (cl-loop for xref in xrefs
-                    maximize (let ((line (xref-location-line
-                                          (xref-item-location xref))))
-                               (and line (1+ (floor (log line 10))))))
-           for line-format = (and max-line-width
-                                  (format "%%%dd: " max-line-width))
+           for max-line = (cl-loop for xref in xrefs
+                                   maximize (xref-location-line
+                                             (xref-item-location xref)))
+           for line-format = (and max-line
+                                  (format "%%%dd: " (1+ (floor (log max-line 
10)))))
            with item-text-props = (list 'mouse-face 'highlight
                                         'keymap xref--button-map
                                         'help-echo
@@ -959,27 +971,27 @@ GROUP is a string for decoration purposes and XREF is an
            do
            (xref--insert-propertized '(face xref-file-header xref-group t)
                                      group "\n")
-           (cl-loop for xref in xrefs do
-                    (pcase-let (((cl-struct xref-item summary location) xref))
-                      (let* ((line (xref-location-line location))
-                             (prefix
-                              (cond
-                               ((not line) "  ")
-                               ((and (equal line prev-line)
-                                     (equal prev-group group))
-                                "")
-                               (t (propertize (format line-format line)
-                                              'face 'xref-line-number)))))
-                        ;; Render multiple matches on the same line, together.
-                        (when (and (equal prev-group group)
-                                   (or (null line)
-                                       (not (equal prev-line line))))
-                          (insert "\n"))
-                        (xref--insert-propertized (nconc (list 'xref-item xref)
-                                                         item-text-props)
-                                                  prefix summary)
-                        (setq prev-line line
-                              prev-group group))))
+           (dolist (xref xrefs)
+             (pcase-let (((cl-struct xref-item summary location) xref))
+               (let* ((line (xref-location-line location))
+                      (prefix
+                       (cond
+                        ((not line) "  ")
+                        ((and (equal line prev-line)
+                              (equal prev-group group))
+                         "")
+                        (t (propertize (format line-format line)
+                                       'face 'xref-line-number)))))
+                 ;; Render multiple matches on the same line, together.
+                 (when (and (equal prev-group group)
+                            (or (null line)
+                                (not (equal prev-line line))))
+                   (insert "\n"))
+                 (xref--insert-propertized (nconc (list 'xref-item xref)
+                                                  item-text-props)
+                                           prefix summary)
+                 (setq prev-line line
+                       prev-group group))))
            (insert "\n"))
   (add-to-invisibility-spec '(ellipsis . t))
   (save-excursion
@@ -1869,34 +1881,36 @@ Such as the current syntax table and the applied syntax 
properties."
                                  syntax-needed)))))
 
 (defun xref--collect-matches-1 (regexp file line line-beg line-end 
syntax-needed)
-  (let (match-pairs matches)
+  (let (matches
+        stop beg end
+        last-beg last-end
+        summary-end)
     (when syntax-needed
       (syntax-propertize line-end))
-    (while (and
-            ;; REGEXP might match an empty string.  Or line.
-            (or (null match-pairs)
-                (> (point) line-beg))
-            (re-search-forward regexp line-end t))
-      (push (cons (match-beginning 0)
-                  (match-end 0))
-            match-pairs))
-    (setq match-pairs (nreverse match-pairs))
-    (while match-pairs
-      (let* ((beg-end (pop match-pairs))
-             (beg-column (- (car beg-end) line-beg))
-             (end-column (- (cdr beg-end) line-beg))
-             (loc (xref-make-file-location file line beg-column))
-             (summary (buffer-substring (if matches (car beg-end) line-beg)
-                                        (if match-pairs
-                                            (caar match-pairs)
-                                          line-end))))
-        (when matches
-          (cl-decf beg-column (- (car beg-end) line-beg))
-          (cl-decf end-column (- (car beg-end) line-beg)))
-        (add-face-text-property beg-column end-column 'xref-match
-                                t summary)
-        (push (xref-make-match summary loc (- end-column beg-column))
-              matches)))
+    (while (not stop)
+      (if (and
+           ;; REGEXP might match an empty string.  Or line.
+           (not (and last-beg (eql end line-beg)))
+           (re-search-forward regexp line-end t))
+          (setq beg (match-beginning 0)
+                end (match-end 0)
+                summary-end beg)
+        (setq stop t
+              summary-end line-end))
+      (when last-beg
+        (let* ((beg-column (- last-beg line-beg))
+               (end-column (- last-end line-beg))
+               (summary-start (if matches last-beg line-beg))
+               (summary (buffer-substring summary-start
+                                          summary-end))
+               (loc (xref-make-file-location file line beg-column)))
+          (add-face-text-property (- last-beg summary-start)
+                                  (- last-end summary-start)
+                                  'xref-match t summary)
+          (push (xref-make-match summary loc (- end-column beg-column))
+                matches)))
+      (setq last-beg beg
+            last-end end))
     (nreverse matches)))
 
 (defun xref--find-file-buffer (file)
diff --git a/lisp/simple.el b/lisp/simple.el
index d7030c0..841983a 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -534,10 +534,7 @@ Other major modes are defined by comparison with this one."
     (dolist (overlay (overlays-in (point-min) (point-max)))
       (delete-overlay overlay))
     (set-text-properties (point-min) (point-max) nil)
-    (setq-local after-change-functions
-                (list
-                 (lambda (begin end _length)
-                   (set-text-properties begin end nil))))))
+    (setq-local yank-excluded-properties t)))
 
 ;; Special major modes to view specially formatted data rather than files.
 
@@ -8429,21 +8426,29 @@ presented."
 
 (defcustom blink-matching-paren t
   "Non-nil means show matching open-paren when close-paren is inserted.
-In addition, if the opening paren is not visible on screen, show
-its position in the echo area.
+If this is non-nil, then when you type a closing delimiter, such as a
+closing parenthesis or brace, Emacs briefly indicates the location
+of the matching opening delimiter.
 
 The valid values are:
 
-  nil               Disable.
-  non-nil           Highlight the opening paren.
-  `jump'            Briefly move cursor to its position.
-  `jump-offscreen'  Briefly move cursor to its position,
-                    even if the opening paren is not on screen."
+  t                 Highlight the matching open-paren if it is visible
+                    in the window, otherwise show the text with matching
+                    open-paren in the echo area.  This is the default.
+  `jump'            If the matching open-paren is visible in the window,
+                    briefly move cursor to its position; otherwise show
+                    the text with matching open-paren in the echo area.
+  `jump-offscreen'  Briefly move cursor to the matching open-paren
+                    even if it is not visible in the window.
+  nil               Don't show the matching open-paren.
+
+Any other non-nil value is handled the same as t."
+
   :type '(choice
           (const :tag "Disable" nil)
-          (const :tag "Highlight" t)
-          (const :tag "Move cursor" jump)
-          (const :tag "Move cursor, even if off screen" jump-offscreen))
+          (const :tag "Highlight open-paren if visible" t)
+          (const :tag "Move cursor to open-paren if visible" jump)
+          (const :tag "Move cursor even if it's off screen" jump-offscreen))
   :group 'paren-blinking)
 
 (defcustom blink-matching-paren-on-screen t
diff --git a/lisp/subr.el b/lisp/subr.el
index 9f0fe42..cca6d53 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1752,6 +1752,7 @@ be a list of the form returned by `event-start' and 
`event-end'."
 (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")
 
 (make-obsolete 'run-window-configuration-change-hook nil "27.1")
 
@@ -3218,7 +3219,7 @@ PROMPT is also updated to show `help-char' like \"(y, n 
or C-h) \",
 where `help-char' is automatically bound to `help-form-show'.
 
 No confirmation of the answer is requested; a single character is
-enough.  SPC also means yes, and DEL means no.
+enough.  RET and SPC also means yes, and DEL means no.
 
 To be precise, this function translates user input into responses
 by consulting the bindings in `query-replace-map'; see the
@@ -4761,14 +4762,12 @@ wherever possible, since it is slow."
 (defsubst looking-at-p (regexp)
   "\
 Same as `looking-at' except this function does not change the match data."
-  (let ((inhibit-changing-match-data t))
-    (looking-at regexp)))
+  (looking-at regexp t))
 
 (defsubst string-match-p (regexp string &optional start)
   "\
 Same as `string-match' except this function does not change the match data."
-  (let ((inhibit-changing-match-data t))
-    (string-match regexp string start)))
+  (string-match regexp string start t))
 
 (defun subregexp-context-p (regexp pos &optional start)
   "Return non-nil if POS is in a normal subregexp context in REGEXP.
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 68afb53..ccecdbc 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -311,12 +311,12 @@ that closes only when clicked on the close button."
         `(menu-item "Duplicate" (lambda () (interactive)
                                   (tab-bar-duplicate-tab
                                    nil ,tab-number))
-                    :help "Duplicate the tab"))
+                    :help "Clone the tab"))
       (define-key-after menu [detach-tab]
         `(menu-item "Detach" (lambda () (interactive)
                                (tab-bar-detach-tab
                                 ,tab-number))
-                    :help "Detach the tab to new frame"))
+                    :help "Move the tab to new frame"))
       (define-key-after menu [close]
         `(menu-item "Close" (lambda () (interactive)
                               (tab-bar-close-tab ,tab-number))
@@ -1208,8 +1208,8 @@ Interactively, ARG selects the ARGth different frame to 
move to."
       (force-mode-line-update t))))
 
 (defun tab-bar-detach-tab (&optional from-number)
-  "Detach tab number FROM-NUMBER to a new frame.
-Interactively or without argument, detach current tab."
+  "Move tab number FROM-NUMBER to a new frame.
+Interactively or without argument, move the current tab."
   (interactive (list (1+ (tab-bar--current-tab-index))))
   (let* ((tabs (funcall tab-bar-tabs-function))
          (tab-index (1- (or from-number (1+ (tab-bar--current-tab-index 
tabs)))))
@@ -1350,7 +1350,7 @@ If FROM-NUMBER is a tab number, a new tab is created from 
that tab."
     (tab-bar-new-tab-to)))
 
 (defun tab-bar-duplicate-tab (&optional arg from-number)
-  "Duplicate the current tab to ARG positions to the right.
+  "Clone the current tab to ARG positions to the right.
 ARG and FROM-NUMBER have the same meaning as in `tab-bar-new-tab'."
   (interactive "P")
   (let ((tab-bar-new-tab-choice nil)
@@ -2243,24 +2243,26 @@ When `switch-to-buffer-obey-display-actions' is non-nil,
 
 ;;; Short aliases and keybindings
 
-(defalias 'tab-new         'tab-bar-new-tab)
-(defalias 'tab-new-to      'tab-bar-new-tab-to)
-(defalias 'tab-duplicate   'tab-bar-duplicate-tab)
-(defalias 'tab-close       'tab-bar-close-tab)
-(defalias 'tab-close-other 'tab-bar-close-other-tabs)
-(defalias 'tab-close-group 'tab-bar-close-group-tabs)
-(defalias 'tab-undo        'tab-bar-undo-close-tab)
-(defalias 'tab-select      'tab-bar-select-tab)
-(defalias 'tab-switch      'tab-bar-switch-to-tab)
-(defalias 'tab-next        'tab-bar-switch-to-next-tab)
-(defalias 'tab-previous    'tab-bar-switch-to-prev-tab)
-(defalias 'tab-last        'tab-bar-switch-to-last-tab)
-(defalias 'tab-recent      'tab-bar-switch-to-recent-tab)
-(defalias 'tab-move        'tab-bar-move-tab)
-(defalias 'tab-move-to     'tab-bar-move-tab-to)
-(defalias 'tab-rename      'tab-bar-rename-tab)
-(defalias 'tab-group       'tab-bar-change-tab-group)
-(defalias 'tab-list        'tab-switcher)
+(defalias 'tab-new             'tab-bar-new-tab)
+(defalias 'tab-new-to          'tab-bar-new-tab-to)
+(defalias 'tab-duplicate       'tab-bar-duplicate-tab)
+(defalias 'tab-detach          'tab-bar-detach-tab)
+(defalias 'tab-window-detach   'tab-bar-move-window-to-tab)
+(defalias 'tab-close           'tab-bar-close-tab)
+(defalias 'tab-close-other     'tab-bar-close-other-tabs)
+(defalias 'tab-close-group     'tab-bar-close-group-tabs)
+(defalias 'tab-undo            'tab-bar-undo-close-tab)
+(defalias 'tab-select          'tab-bar-select-tab)
+(defalias 'tab-switch          'tab-bar-switch-to-tab)
+(defalias 'tab-next            'tab-bar-switch-to-next-tab)
+(defalias 'tab-previous        'tab-bar-switch-to-prev-tab)
+(defalias 'tab-last            'tab-bar-switch-to-last-tab)
+(defalias 'tab-recent          'tab-bar-switch-to-recent-tab)
+(defalias 'tab-move            'tab-bar-move-tab)
+(defalias 'tab-move-to         'tab-bar-move-tab-to)
+(defalias 'tab-rename          'tab-bar-rename-tab)
+(defalias 'tab-group           'tab-bar-change-tab-group)
+(defalias 'tab-list            'tab-switcher)
 
 (define-key tab-prefix-map "n" 'tab-duplicate)
 (define-key tab-prefix-map "N" 'tab-new-to)
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index 7ca2fb8..b5f53ba 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -856,10 +856,10 @@ label prefix determines the wording of a reference."
          (label (car toc)) newlabel)
     (if (not (stringp label))
         (error "This is not a label entry"))
-    (setq newlabel (read-string (format "Rename label \"%s\" to:" label)))
+    (setq newlabel (read-string (format "Rename label \"%s\" to: " label)))
     (if (assoc newlabel (symbol-value reftex-docstruct-symbol))
         (if (not (y-or-n-p
-                  (format-message "Label `%s' exists.  Use anyway? " label)))
+                  (format-message "Label `%s' exists.  Use anyway? " 
newlabel)))
             (error "Abort")))
     (save-excursion
       (save-window-excursion
diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el
index 6da4011..f5d64ae 100644
--- a/lisp/tool-bar.el
+++ b/lisp/tool-bar.el
@@ -290,6 +290,8 @@ holds a keymap."
       "Specify on which side the tool bar shall be.
 Possible values are `top' (tool bar on top), `bottom' (tool bar at bottom),
 `left' (tool bar on left) and `right' (tool bar on right).
+This option has effect only on graphical frames and only
+if Emacs was built with GTK.
 Customize `tool-bar-mode' if you want to show or hide the tool bar."
       :version "24.1"
       :type '(choice (const top)
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 0ed9f7c..6bec9ed 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -672,7 +672,6 @@ Return the byte's value as an integer."
     (let* ((result nil)
            (flen (length fname))
            (case-fold-search nil)
-           (inhibit-changing-match-data t)
            ;; Find a conservative bound for the loop below by using
            ;; Boyer-Moore on the raw dirstate without parsing it; we
            ;; know we can't possibly find fname _after_ the last place
@@ -976,10 +975,9 @@ REPO must be the directory name of an hg repository."
   "Test whether the ignore pattern set HGIP says to ignore FILENAME.
 FILENAME must be the file's true absolute name."
   (let ((patterns (vc-hg--ignore-patterns-ignore-patterns hgip))
-        (inhibit-changing-match-data t)
         (ignored nil))
     (while (and patterns (not ignored))
-      (setf ignored (string-match (pop patterns) filename)))
+      (setf ignored (string-match-p (pop patterns) filename)))
     ignored))
 
 (defvar vc-hg--cached-ignore-patterns nil
@@ -1043,7 +1041,8 @@ Avoids the need to repeatedly scan dirstate on repeated 
calls to
              (equal size (pop cache))
              (equal ascii-fname (pop cache)))
         (pop cache)
-      (let ((result (vc-hg--raw-dirstate-search dirstate ascii-fname)))
+      (let ((result (save-match-data
+                      (vc-hg--raw-dirstate-search dirstate ascii-fname))))
         (setf vc-hg--dirstate-scan-cache
               (list dirstate mtime size ascii-fname result))
         result))))
diff --git a/make-dist b/make-dist
index 7074bb8..eb04015 100755
--- a/make-dist
+++ b/make-dist
@@ -366,9 +366,9 @@ possibly_non_vc_files="
   src/config.in
 "$(
   find admin doc etc lisp \
-    \( -name '*.el' -o -name '*.elc' -o -name '*.map' -o -name '*.stamp' \
-       -o -name '*.texi' -o -name '*.tex' -o -name '*.txt' \) \
-    ! -name 'site-init*' ! -name 'site-load*' ! -name 'default*'
+   \( -name '*.el' -o -name '*.elc' -o -name '*.map' -o -name '*.stamp' \
+      -o -name '*.texi' -o -name '*.tex' -o -name '*.txt' -o -name '*.pdf' \) \
+   ! -name 'site-init*' ! -name 'site-load*' ! -name 'default*'
 ) || exit
 
 if [ $with_info = yes ]; then
diff --git a/src/Makefile.in b/src/Makefile.in
index b8d0e7b..6d75e35 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -803,8 +803,17 @@ elnlisp := $(addprefix ${lispsource}/,${elnlisp}) 
$(lisp:.elc=.eln)
        @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="../src/emacs$(EXEEXT)"\
                THEFILE=$< $<n
 
+## FIXME: this is fragile!  We lie to Make about the files produced by
+## this rule, and we rely on the absence of the native-lisp directory
+## to trigger it.  This means that if anything goes wrong during
+## native compilation, the only way to trigger it again is to remove
+## the directory and re-native-compile everything.  The main
+## underlying problem is that the name of the subdirectory of
+## native-lisp where the *.eln files will be produced, and the exact
+## names of those *.eln files, cannot be known in advance; we must ask
+## Emacs to produce them.
 ../native-lisp: | $(pdmp)
-       if test ! -d $@; then \
+       @if test ! -d $@; then \
          mkdir $@ && $(MAKE) $(AM_V_NO_PD) $(elnlisp); \
          if test $(SYSTEM_TYPE) = cygwin; then \
            find $@ -name '*.eln' | rebase -v -O -T -; \
diff --git a/src/buffer.c b/src/buffer.c
index c5b2736..648d722 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1434,7 +1434,7 @@ and `buffer-file-truename' are non-nil.  */)
 DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
        Srestore_buffer_modified_p, 1, 1, 0,
        doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's 
mode line.
-This function also locks and unlocks the file visited by the buffer,
+This function also locks or unlocks the file visited by the buffer,
 if both `buffer-file-truename' and `buffer-file-name' are non-nil.
 
 It is not ensured that mode lines will be updated to show the modified
diff --git a/src/comp.c b/src/comp.c
index bc1adcf..5b947fc 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -4123,7 +4123,7 @@ one for the file name and another for its contents, 
followed by .eln.  */)
   FOR_EACH_TAIL (lds_re_tail)
     {
       Lisp_Object match_idx =
-       Fstring_match (XCAR (lds_re_tail), filename, Qnil);
+       Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil);
       if (EQ (match_idx, make_fixnum (0)))
        {
          filename =
@@ -5260,7 +5260,8 @@ file_in_eln_sys_dir (Lisp_Object filename)
     eln_sys_dir = XCAR (tmp);
   return !NILP (Fstring_match (Fregexp_quote (Fexpand_file_name (eln_sys_dir,
                                                                 Qnil)),
-                              Fexpand_file_name (filename, Qnil), Qnil));
+                              Fexpand_file_name (filename, Qnil),
+                              Qnil, Qnil));
 }
 
 /* Load related routines.  */
diff --git a/src/composite.h b/src/composite.h
index 67e8720..945f261 100644
--- a/src/composite.h
+++ b/src/composite.h
@@ -254,6 +254,10 @@ composition_valid_p (ptrdiff_t start, ptrdiff_t end, 
Lisp_Object prop)
 #define LGSTRING_HEADER(lgs) AREF (lgs, 0)
 #define LGSTRING_SET_HEADER(lgs, header) ASET (lgs, 0, header)
 
+/* LGSTRING_FONT retrieves the font used for LGSTRING, if we are going
+   to display it on a GUI frame.  On text-mode frames, that slot
+   stores the coding-system that should be used to write output to the
+   frame's terminal.  */
 #define LGSTRING_FONT(lgs) AREF (LGSTRING_HEADER (lgs), 0)
 #define LGSTRING_CHAR(lgs, i) AREF (LGSTRING_HEADER (lgs), (i) + 1)
 #define LGSTRING_CHAR_LEN(lgs) (ASIZE (LGSTRING_HEADER (lgs)) - 1)
diff --git a/src/dispextern.h b/src/dispextern.h
index 6aefe43..08dac5d 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1326,7 +1326,9 @@ struct glyph_string
   /* The area within row.  */
   enum glyph_row_area area;
 
-  /* Characters to be drawn, and number of characters.  */
+  /* Characters to be drawn, and number of characters.  Note that
+     NCHARS can be zero if this is a composition glyph string, as
+     evidenced by FIRST_GLYPH->type.  */
   unsigned *char2b;
   int nchars;
 
diff --git a/src/keyboard.c b/src/keyboard.c
index 4f3232d..9a50a5e 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5130,7 +5130,8 @@ make_lispy_position (struct frame *f, Lisp_Object x, 
Lisp_Object y,
       window_or_frame = Qnil;
     }
 #endif
-  if (!FRAME_WINDOW_P (f)
+  if (f
+      && !FRAME_WINDOW_P (f)
       && FRAME_TAB_BAR_LINES (f) > 0
       && my >= FRAME_MENU_BAR_LINES (f)
       && my < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))
diff --git a/src/minibuf.c b/src/minibuf.c
index 5455a93..0dc340e 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1684,7 +1684,7 @@ is used to further constrain the set of candidates.  */)
                    specbind (Qcase_fold_search,
                              completion_ignore_case ? Qt : Qnil);
                  }
-               tem = Fstring_match (XCAR (regexps), eltstring, zero);
+               tem = Fstring_match (XCAR (regexps), eltstring, zero, Qnil);
                if (NILP (tem))
                  break;
              }
@@ -1948,7 +1948,7 @@ with a space are ignored unless STRING itself starts with 
a space.  */)
                    specbind (Qcase_fold_search,
                              completion_ignore_case ? Qt : Qnil);
                  }
-               tem = Fstring_match (XCAR (regexps), eltstring, zero);
+               tem = Fstring_match (XCAR (regexps), eltstring, zero, Qnil);
                if (NILP (tem))
                  break;
              }
@@ -2163,7 +2163,7 @@ the values STRING, PREDICATE and `lambda'.  */)
        {
           /* We can test against STRING, because if we got here, then
              the element is equivalent to it.  */
-          if (NILP (Fstring_match (XCAR (regexps), string, Qnil)))
+          if (NILP (Fstring_match (XCAR (regexps), string, Qnil, Qnil)))
            return unbind_to (count, Qnil);
        }
       unbind_to (count, Qnil);
diff --git a/src/search.c b/src/search.c
index 08f1e94..66e77d4 100644
--- a/src/search.c
+++ b/src/search.c
@@ -260,7 +260,7 @@ compile_pattern (Lisp_Object pattern, struct re_registers 
*regp,
 
 
 static Lisp_Object
-looking_at_1 (Lisp_Object string, bool posix)
+looking_at_1 (Lisp_Object string, bool posix, bool modify_data)
 {
   Lisp_Object val;
   unsigned char *p1, *p2;
@@ -278,11 +278,11 @@ looking_at_1 (Lisp_Object string, bool posix)
   CHECK_STRING (string);
 
   /* Snapshot in case Lisp changes the value.  */
-  bool preserve_match_data = NILP (Vinhibit_changing_match_data);
+  bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
 
   struct regexp_cache *cache_entry = compile_pattern (
     string,
-    preserve_match_data ? &search_regs : NULL,
+    modify_match_data ? &search_regs : NULL,
     (!NILP (BVAR (current_buffer, case_fold_search))
      ? BVAR (current_buffer, case_canon_table) : Qnil),
     posix,
@@ -316,7 +316,7 @@ looking_at_1 (Lisp_Object string, bool posix)
   re_match_object = Qnil;
   i = re_match_2 (&cache_entry->buf, (char *) p1, s1, (char *) p2, s2,
                  PT_BYTE - BEGV_BYTE,
-                 preserve_match_data ? &search_regs : NULL,
+                 modify_match_data ? &search_regs : NULL,
                  ZV_BYTE - BEGV_BYTE);
 
   if (i == -2)
@@ -326,7 +326,7 @@ looking_at_1 (Lisp_Object string, bool posix)
     }
 
   val = (i >= 0 ? Qt : Qnil);
-  if (preserve_match_data && i >= 0)
+  if (modify_match_data && i >= 0)
   {
     for (i = 0; i < search_regs.num_regs; i++)
       if (search_regs.start[i] >= 0)
@@ -343,35 +343,37 @@ looking_at_1 (Lisp_Object string, bool posix)
   return unbind_to (count, val);
 }
 
-DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0,
+DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 2, 0,
        doc: /* Return t if text after point matches regular expression REGEXP.
-This function modifies the match data that `match-beginning',
-`match-end' and `match-data' access; save and restore the match
-data if you want to preserve them.  */)
-  (Lisp_Object regexp)
+By default, this function modifies the match data that
+`match-beginning', `match-end' and `match-data' access.  If
+INHIBIT-MODIFY is non-nil, don't modify the match data.  */)
+  (Lisp_Object regexp, Lisp_Object inhibit_modify)
 {
-  return looking_at_1 (regexp, 0);
+  return looking_at_1 (regexp, 0, NILP (inhibit_modify));
 }
 
-DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 1, 0,
+DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 2, 0,
        doc: /* Return t if text after point matches REGEXP according to Posix 
rules.
 Find the longest match, in accordance with Posix regular expression rules.
-This function modifies the match data that `match-beginning',
-`match-end' and `match-data' access; save and restore the match
-data if you want to preserve them.  */)
-  (Lisp_Object regexp)
+
+By default, this function modifies the match data that
+`match-beginning', `match-end' and `match-data' access.  If
+INHIBIT-MODIFY is non-nil, don't modify the match data.  */)
+  (Lisp_Object regexp, Lisp_Object inhibit_modify)
 {
-  return looking_at_1 (regexp, 1);
+  return looking_at_1 (regexp, 1, NILP (inhibit_modify));
 }
 
 static Lisp_Object
 string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
-               bool posix)
+               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;
 
   if (running_asynch_code)
     save_search_regs ();
@@ -400,8 +402,7 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
                         BVAR (current_buffer, case_eqv_table));
 
   bufp = &compile_pattern (regexp,
-                           (NILP (Vinhibit_changing_match_data)
-                            ? &search_regs : NULL),
+                           (modify_match_data ? &search_regs : NULL),
                            (!NILP (BVAR (current_buffer, case_fold_search))
                             ? BVAR (current_buffer, case_canon_table) : Qnil),
                            posix,
@@ -410,18 +411,17 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
   val = re_search (bufp, SSDATA (string),
                   SBYTES (string), pos_byte,
                   SBYTES (string) - pos_byte,
-                  (NILP (Vinhibit_changing_match_data)
-                   ? &search_regs : NULL));
+                  (modify_match_data ? &search_regs : NULL));
 
   /* Set last_thing_searched only when match data is changed.  */
-  if (NILP (Vinhibit_changing_match_data))
+  if (modify_match_data)
     last_thing_searched = Qt;
 
   if (val == -2)
     matcher_overflow ();
   if (val < 0) return Qnil;
 
-  if (NILP (Vinhibit_changing_match_data))
+  if (modify_match_data)
     for (i = 0; i < search_regs.num_regs; i++)
       if (search_regs.start[i] >= 0)
        {
@@ -434,32 +434,42 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
   return make_fixnum (string_byte_to_char (string, val));
 }
 
-DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0,
+DEFUN ("string-match", Fstring_match, Sstring_match, 2, 4, 0,
        doc: /* Return index of start of first match for REGEXP in STRING, or 
nil.
 Matching ignores case if `case-fold-search' is non-nil.
 If third arg START is non-nil, start search at that index in STRING.
-For index of first char beyond the match, do (match-end 0).
-`match-end' and `match-beginning' also give indices of substrings
-matched by parenthesis constructs in the pattern.
 
-You can use the function `match-string' to extract the substrings
-matched by the parenthesis constructions in REGEXP. */)
-  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start)
+If INHIBIT-MODIFY is non-nil, match data is not changed.
+
+If INHIBIT-MODIFY is nil or missing, match data is changed, and
+`match-end' and `match-beginning' give indices of substrings matched
+by parenthesis constructs in the pattern.  You can use the function
+`match-string' to extract the substrings matched by the parenthesis
+constructions in REGEXP.  For index of first char beyond the match, do
+(match-end 0).  */)
+  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
+   Lisp_Object inhibit_modify)
 {
-  return string_match_1 (regexp, string, start, 0);
+  return string_match_1 (regexp, string, start, 0, NILP (inhibit_modify));
 }
 
-DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 3, 0,
+DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 4, 0,
        doc: /* Return index of start of first match for Posix REGEXP in 
STRING, or nil.
 Find the longest match, in accord with Posix regular expression rules.
 Case is ignored if `case-fold-search' is non-nil in the current buffer.
-If third arg START is non-nil, start search at that index in STRING.
-For index of first char beyond the match, do (match-end 0).
-`match-end' and `match-beginning' also give indices of substrings
-matched by parenthesis constructs in the pattern.  */)
-  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start)
+
+If INHIBIT-MODIFY is non-nil, match data is not changed.
+
+If INHIBIT-MODIFY is nil or missing, match data is changed, and
+`match-end' and `match-beginning' give indices of substrings matched
+by parenthesis constructs in the pattern.  You can use the function
+`match-string' to extract the substrings matched by the parenthesis
+constructions in REGEXP.  For index of first char beyond the match, do
+(match-end 0).  */)
+  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
+   Lisp_Object inhibit_modify)
 {
-  return string_match_1 (regexp, string, start, 1);
+  return string_match_1 (regexp, string, start, 1, NILP (inhibit_modify));
 }
 
 /* Match REGEXP against STRING using translation table TABLE,
diff --git a/src/term.c b/src/term.c
index 0858f81..6f0b827 100644
--- a/src/term.c
+++ b/src/term.c
@@ -550,7 +550,7 @@ encode_terminal_code (struct glyph *src, int src_len,
       if (src->type == COMPOSITE_GLYPH)
        {
          struct composition *cmp;
-         Lisp_Object gstring;
+         Lisp_Object gstring UNINIT;
          int i;
 
          nbytes = buf - encode_terminal_src;
diff --git a/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el 
b/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el
index 14c8e84..9b41fb5 100644
--- a/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el
+++ b/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el
@@ -1,3 +1,5 @@
+;;; simple-shorthand-test.el ---   -*- lexical-binding: t; -*-
+
 (defun f-test ()
   (let ((read-symbol-shorthands '(("foo-" . "bar-"))))
     (with-temp-buffer



reply via email to

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