emacs-elpa-diffs
[Top][All Lists]
Advanced

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

[nongnu] elpa/eat 06e45d68b9 01/12: Implement the terminal


From: ELPA Syncer
Subject: [nongnu] elpa/eat 06e45d68b9 01/12: Implement the terminal
Date: Sun, 27 Nov 2022 15:59:29 -0500 (EST)

branch: elpa/eat
commit 06e45d68b9c1066cd3a170cb786a0693656d28a2
Author: Akib Azmain Turja <akib@disroot.org>
Commit: Akib Azmain Turja <akib@disroot.org>

    Implement the terminal
    
    This includes everything written from 2022-08-15 up to now.
    * .dir-locals.el:
    * CONTRIBUTE:
    * COPYING:
    * Makefile:
    * NEWS:
    * README.org:
    * eat-tests.el:
    * eat.el:
    * eat.texi:
    * eat.ti:
    * fdl.texi:
    * gitlog-to-changelog:
    * gpl.texi:
    * make-changelog:
    * texinfo.tex:
    New file.
---
 .dir-locals.el      |     4 +
 CONTRIBUTE          |   252 ++
 COPYING             |   674 +++
 Makefile            |    39 +
 NEWS                |    32 +
 README.org          |   137 +
 e/eat-256color      |   Bin 0 -> 2216 bytes
 e/eat-color         |   Bin 0 -> 2218 bytes
 e/eat-mono          |   Bin 0 -> 2008 bytes
 e/eat-truecolor     |   Bin 0 -> 2223 bytes
 eat-tests.el        |  6230 +++++++++++++++++++++++++++
 eat.el              |  6662 +++++++++++++++++++++++++++++
 eat.texi            |  1001 +++++
 eat.ti              |   206 +
 fdl.texi            |   505 +++
 gitlog-to-changelog |   516 +++
 gpl.texi            |   717 ++++
 make-changelog      |    40 +
 texinfo.tex         | 11614 ++++++++++++++++++++++++++++++++++++++++++++++++++
 19 files changed, 28629 insertions(+)

diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000000..433dfac2d0
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,4 @@
+;;; Directory Local Variables            -*- no-byte-compile: t -*-
+;;; For more information see (info "(emacs) Directory Variables")
+
+((sh-mode . ((sh-basic-offset . 2))))
diff --git a/CONTRIBUTE b/CONTRIBUTE
new file mode 100644
index 0000000000..67aa6e5c73
--- /dev/null
+++ b/CONTRIBUTE
@@ -0,0 +1,252 @@
+* How developers contribute to Eat
+
+Here is how software developers can contribute to Eat.
+
+** Documenting your changes
+
+Any change that matters to end-users should have an entry in etc/NEWS.
+Try to start each NEWS entry with a sentence that summarizes the entry
+and takes just one line -- this will allow to read NEWS in Outline
+mode after hiding the body of each entry.
+
+Doc-strings should be updated together with the code.
+
+Think about whether your change requires updating the manuals.  If you
+know it does not, mark the NEWS entry with "---".  If you know
+that *all* the necessary documentation updates have been made as part
+of your changes or those by others, mark the entry with "+++".
+Otherwise do not mark it.
+
+If your change requires updating the manuals to document new
+functions/commands/variables/faces, then use the proper Texinfo
+command to index them; for instance, use @vindex for variables and
+@findex for functions/commands.  For the full list of predefined indices, see
+https://www.gnu.org/software/texinfo/manual/texinfo/html_node/Predefined-Indices.html
+or run the shell command 'info "(texinfo)Predefined Indices"'.
+
+We prefer American English both in doc strings and in the manuals,
+just like Emacs.  That includes both spelling (e.g., "behavior", not
+"behaviour") and the convention of leaving 2 spaces between sentences.
+
+Eat follows Emacs doc style.  For more specific tips on Emacs's doc style, see
+https://www.gnu.org/software/emacs/manual/html_node/elisp/Documentation-Tips.html
+Use 'checkdoc' to check for documentation errors before submitting a
+patch.
+
+** Testing your changes
+
+Please test your changes before committing them or sending them to the
+list.  "make check" runs all the tests.  If possible, add a new test
+along with any bug fix or new functionality you commit (of course,
+some changes cannot be easily tested, but the terminal emulator part
+should be as much tested as possible).
+
+Eat uses ERT, Emacs Lisp Regression Testing, for testing.  See
+https://www.gnu.org/software/emacs/manual/html_node/ert/ or run
+'info "(ert)"' for more information on writing and running tests.
+
+If your test lasts longer than some few seconds, mark it in its
+'ert-deftest' definition with ":tags '(:expensive-test)".
+
+** Commit messages
+
+Ordinarily, a change you commit should contain a log entry in its
+commit message and should not touch the repository's ChangeLog files.
+Here is an example commit message (indented):
+
+       Deactivate shifted region
+
+       Do not silently extend a region that is not highlighted;
+       this can happen after a shift (Bug#19003).
+       * doc/emacs/mark.texi (Shift Selection): Document the change.
+       * lisp/window.el (handle-select-window):
+       * src/frame.c (Fhandle_switch_frame, Fselected_frame):
+       Deactivate the mark.
+
+Here are guidelines for formatting commit message:
+
+- Start with a single unindented summary line explaining the change;
+  do not end this line with a period.  If possible, try to keep the
+  summary line to 50 characters or fewer; this is for compatibility
+  with certain Git commands that print that line in width-constrained
+  contexts.
+
+  If the summary line starts with a semicolon and a space "; ", the
+  commit message will be ignored when generating the ChangeLog file.
+  Use this for minor commits that do not need separate ChangeLog
+  entries, such as changes in etc/NEWS.
+
+- After the summary line, there should be an empty line.
+
+- Unindented ChangeLog entries normally come next.  However, if the
+  commit couldn't be properly summarized in the brief summary line,
+  you can put a paragraph (after the empty line and before the
+  individual ChangeLog entries) that further describes the commit.
+
+- Lines in ChangeLog entries should preferably be not longer than 63
+  characters, and must not exceed 78 characters, unless they consist
+  of a single word of at most 140 characters; this 78/140 limit is
+  enforced by a commit hook.
+
+- If only a single file is changed, the summary line can be the normal
+  file first line (starting with the asterisk).  Then there is no
+  individual files section.
+
+- If the commit has more than one author, the commit message should
+  contain separate lines to mention the other authors, like the
+  following:
+
+       Co-authored-by: Joe Schmoe <j.schmoe@example.org>
+
+- If the commit is a tiny change that is exempt from copyright paperwork,
+  the commit message should contain a separate line like the following:
+
+       Copyright-paperwork-exempt: yes
+
+- The commit message should not contain any reference to any Codeberg
+  issue.
+
+- The commit message should contain "Bug#NNNNN" if it is related to
+  bug number NNNNN in the debbugs database.  This string is often
+  parenthesized, as in "(Bug#19003)".
+
+- When citing URLs, prefer https: to http: when either will do.
+
+- Commit messages should contain only printable UTF-8 characters.
+
+- Commit messages should not contain the "Signed-off-by:" lines that
+  are used in some other projects.
+
+- Any lines of the commit message that start with "; " are omitted
+  from the generated ChangeLog.
+
+- Explaining the rationale for a design choice is best done in comments
+  in the source code.  However, sometimes it is useful to describe just
+  the rationale for a change; that can be done in the commit message
+  between the summary line and the file entries.
+
+- Eat follows the GNU coding standards for ChangeLogs: see
+  https://www.gnu.org/prep/standards/html_node/Change-Logs.html
+  or run 'info "(standards)Change Logs"'.
+
+- Some commenting rules in the GNU coding standards also apply
+  to ChangeLog entries: they must be in English, and be complete
+  sentences starting with a capital and ending with a period (except
+  the summary line should not end in a period).  See
+  https://www.gnu.org/prep/standards/html_node/Comments.html
+  or run 'info "(standards)Comments"'.  American English is preferred
+  in Eat, just like Emacs; that includes spelling and leaving 2 blanks
+  between sentences.
+
+  They are preserved indefinitely, and have a reasonable chance of
+  being read in the future, so it's better that they have good
+  presentation.
+
+- Use the present tense; describe "what the change does", not "what
+  the change did".
+
+- Preferred form for several entries with the same content:
+
+       * lisp/menu-bar.el (clipboard-yank, clipboard-kill-ring-save)
+       (clipboard-kill-region):
+       * lisp/eshell/esh-io.el (eshell-virtual-targets)
+       (eshell-clipboard-append):
+       Replace option gui-select-enable-clipboard with
+       select-enable-clipboard; renamed October 2014.  (Bug#25145)
+
+  (Rather than anything involving "ditto" and suchlike.)
+
+- There is no standard or recommended way to identify revisions in
+  ChangeLog entries.  Using Git SHA1 values limits the usability of
+  the references to Git, and will become much less useful if Eat.
+  switches to a different VCS.  So we recommend against doing only that.
+
+  One way to identify revisions is by quoting their summary line.
+  Prefixing the summary with the commit date can give useful context
+  (use 'git show -s "--pretty=format:%cd \"%s\"" --date=short HASH' to
+  produce that).  Often, "my previous commit" will suffice.
+
+- There is no need to mention files such as NEWS and MAINTAINERS, or
+  to indicate regeneration of files such as 'lib/gnulib.mk', in the
+  ChangeLog entry.  "There is no need" means you don't have to, but
+  you can if you want to.
+
+** Committing your changes.
+
+Your commit message must meet the following critiria:
+
+- commit log message must not be empty;
+- the first line of the commit log message doesn't start with
+  whitespace characters;
+- the second line of the commit log message must be empty;
+- commit log message should include only valid printable ASCII and
+  UTF-8 characters;
+- commit log message lines must be shorter than 79 characters, unless
+  a line consists of a single long word, in which case that word can
+  be up to 140 characters long;
+- there shouldn't be any "Signed-off-by:" tags in the commit log
+  message, and "git commit" should not be invoked with the '-s' option
+  (which automatically adds "Signed-off-by:");
+- if the commit adds new files, the file names must not begin with
+  '-' and must consist of ASCII letters, digits, and characters of the
+  set [-+./_];
+- the changes don't include unresolved merge conflict markers;
+- the changes don't introduce whitespace errors: trailing whitespace,
+  lines that include nothing but whitespace characters, and indented
+  lines where a SPC character is immediately followed by a TAB in the
+  line's initial indentation
+
+This is not enforced right now, but it'll happen eventually.
+
+** Committing changes by others
+
+If committing changes written by someone else, commit in their name,
+not yours.  You can use 'git commit --author="AUTHOR"' to specify a
+change's author.  When using Emacs VC to commit, the author can be
+specified in the log-edit buffer by adding an "Author: AUTHOR" header
+line (set 'log-edit-setup-add-author' non-nil to have this header line
+added automatically).  Note that the validity checks described in the
+previous section are still applied, so you will have to correct any
+problems they uncover in the changes submitted by others.
+
+** git vs rename
+
+Git does not explicitly represent a file renaming; it uses a percent
+changed heuristic to deduce that a file was renamed.  So if you are
+planning to make extensive changes to a file after renaming it (or
+moving it to another directory), you should:
+
+- Create a feature branch.
+
+- Commit the rename without any changes.
+
+- Make other changes.
+
+- Merge the feature branch to the master branch, instead of squashing
+  the commits into one.  The commit message on this merge should
+  summarize the renames and all the changes.
+
+
+
+Adapted from CONTRIBUTE in Emacs source tree.
+
+This file is part of Eat and is not part of GNU Emacs.
+
+Eat is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Eat is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+Local variables:
+mode: outline
+paragraph-separate: "[         ]*$"
+coding: utf-8
+end:
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000..f288702d2f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..a0e2566934
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,39 @@
+# Makefile --- Build configuration
+
+# Copyright (C) 2022 Akib Azmain Turja.
+
+# This file is not part of GNU Emacs.
+
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# For a full copy of the GNU General Public License
+# see <https://www.gnu.org/licenses/>.
+
+EMACS ?= emacs
+
+all: eat.elc terminfo check changelog
+
+terminfo: e/eat-mono e/eat-color eat-256color e/eat-truecolor
+
+check: eat.el
+       $(EMACS) -batch -l eat.el -l eat-tests.el \
+               -f ert-run-tests-batch-and-exit
+
+changelog:
+       ./make-changelog
+
+.PHONY: all terminfo check changelog
+
+eat.elc:
+       $(EMACS) -batch --eval '(byte-compile-file "eat.el")'
+
+e/eat-mono e/eat-color eat-256color e/eat-truecolor:
+       env TERMINFO=. tic -x eat.ti
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000000..125ea3a276
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,32 @@
+Eat NEWS -- History of user-visible changes
+
+Copyright (C) 2022 Akib Azmain Turja.
+See the end of the file for license conditions.
+
+This file is about changes in Eat.
+
+Note:
++++ indicates that Eat manual have been updated.
+--- means no change in the manuals is needed.
+When you add a new item, use the appropriate mark if you are sure it
+applies, and please also update docstrings as needed.
+
+
+----------------------------------------------------------------------
+Adapted from etc/NEWS in Emacs source tree.
+
+This file is part of Eat and is not part of GNU Emacs.
+
+Eat is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Eat is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
diff --git a/README.org b/README.org
new file mode 100644
index 0000000000..d1604689eb
--- /dev/null
+++ b/README.org
@@ -0,0 +1,137 @@
+#+title: Eat: Emulate A Terminal
+
+Eat's name self-explainary, it stands for "Emulate A Terminal".  Eat
+is a terminal emulator.  It can run most (if not all) full-screen
+terminal programs, including Emacs.
+
+It is pretty fast, more than three times faster than Term, despite
+being implemented entirely in Emacs Lisp.  So fast that you can
+comfortably run Emacs inside Eat, or even use your Emacs as a terminal
+multiplexer.
+
+It has many feature that other Emacs terminal emulator still don't
+have, for example complete mouse support.
+
+It flickers less than other Emacs terminal emulator, so you get more
+performance and a smooth experience.
+
+* Usage
+
+To start Eat, run =M-x eat=.  Eat has three keybinding modes:
+
+- "emacs" mode: No special keybinding, except the following:
+
+  - =C-c C-s=: Switch to semi-char mode.
+  - =C-c C-j=: Switch to char mode.
+  - =C-c C-k=: Kill process.
+
+- "semi-char" mode: Most keys are bound to send the key to the
+  terminal, except the following keys: =C-\=, =C-c=, =C-x=, =C-g=,
+  =C-h=, =C-M-c=, =C-u=, =C-q=, =M-x=, =M-:=, =M-!=, =M-&=.  The
+  following special keybinding are available:
+
+  - =C-q=: Send next key to the terminal.
+  - =C-y=: Like `yank', but send the text to the terminal.
+  - =M-y=: Like `yank-pop', but send the text to the terminal.
+  - =C-c C-k=: Kill process.
+
+- "char" mode: All supported keys are bound to send the key to the
+  terminal, except =C-M-m= or =M-RET=, which is bound to switch to
+  semi-char mode.
+
+If you like Eshell, then there is a good news for you.  Eat integrates
+with Eshell.  Eat has two global minor modes for Eshell:
+
+- ~eat-eshell-visual-command-mode~: Run visual commands with Eat
+  instead of Term.
+
+- ~eat-eshell-mode~: Run Eat inside Eshell.  After enabling this, you
+  can run full-screen terminal programs directly in Eshell.  You have
+  the above three keybinding modes here too, except that =C-c C-k= is
+  not special (i.e. not bound by Eat) in "emacs" mode and "line" mode.
+
+You can add any of these to ~eshell-first-time-mode-hook~ like the
+following:
+
+#+begin_src emacs-lisp
+;; For `eat-eshell-visual-command-mode'.
+(add-hook 'eshell-first-time-mode-hook
+          #'eat-eshell-visual-command-mode)
+
+;; For `eat-eshell-mode'.
+(add-hook 'eshell-first-time-mode-hook #'eat-eshell-mode)
+#+end_src
+
+* Installation
+
+Eat requires at Emacs 28.1 or above.  Eat isn't available on any ELPA
+right now.  So, you have to follow one of the following methods:
+
+** Quelpa
+
+#+begin_src emacs-lisp
+(quelpa (eat :fetcher git
+             :url "https://codeberg.org/akib/emacs-iwindow.git";
+             :files ("*.el" "dir"
+                     "*.info" "*.texi"
+                     "*.ti" ("e" "e/*")))
+#+end_src
+
+** Manual
+
+Clone the repository and put it in your ~load-path~.
+
+* Comparison With Other Terminal Emulators
+
+** Term
+
+Term is the Emacs built-in terminal emulator.  Its terminal emulation
+is pretty good too.  But it's slow.  It is so slow that Eat can beat
+native-compiled Term even without byte-compilation, and when Eat is
+byte-compiled, Eat is more than three times fast.  Also, Term
+flickers, just try to run =emacs -nw= in it.  It doesn't support
+remote connections, for example over Tramp.  However, it has "line"
+mode, which Eat still doesn't have.  If you want line mode in a
+terminal, or use an old version of Emacs, you can use Term, but
+Coterm + Shell is probably a better choice in case your Emacs version
+is 26.1 or above.
+
+** Vterm
+
+Vterm is powered by a C library, libvterm.  For this reason, it can
+process huge amount of text quickly.  It is about 1.5 times faster
+than Eat (byte-compiled or native-compiled) (and about 2.75 faster
+then Eat without byte-compilation).  But it doesn't have a char mode
+(however you can make a char mode spending some effort).  And it too
+flickers like Term, so despite being much faster that Eat, it seems to
+be slow.  If you need your terminal to handle huge bursts (megabytes)
+of data, you should Vterm.
+
+** Coterm + Shell
+
+Coterm adds terminal emulation to Shell mode.  Although the terminal
+Coterm emulates is same as Term, it is much faster, about three times,
+just a bit slow than Eat.  However, it too flickers like other
+terminals.  Since it's an upgrade to Shell, you get all the features
+of Shell like "line" mode, completion using your favorite completion
+UI (Company, Corfu, etc), etc.  Most of these features are available
+in Eat-Eshell-Mode as Eshell is similar to Shell, however it's not
+Shell mode.  Recommended if you like Shell.
+
+* Acknowledgements
+
+This wouldn't have been possible if the following awesome softwares
+didn't exist:
+
+- [[https://gnu.org][GNU Operating System]]
+- [[https://st.suckless.org/][St]]
+- [[https://sw.kovidgoyal.net/kitty/][Kitty]]
+- [[https://invisible-island.net/xterm/][XTerm]]
+- [[https://www.gnu.org/software/linux-libre/][Linux-libre]]
+- 
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Terminal-emulator.html][Term]]
+- [[https://repo.or.cz/emacs-coterm.git][Coterm]]
+- 
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Interactive-Shell.html][Shell]]
+- [[https://github.com/akermu/emacs-libvterm][Vterm]]
+- 
[[https://www.gnu.org/software/emacs/manual/html_node/eshell/index.html][Eshell]]
+- Numerous terminal programs
+- And obviously, [[https://www.gnu.org/software/emacs/][GNU Emacs]]
diff --git a/e/eat-256color b/e/eat-256color
new file mode 100644
index 0000000000..dda98bd68c
Binary files /dev/null and b/e/eat-256color differ
diff --git a/e/eat-color b/e/eat-color
new file mode 100644
index 0000000000..53ed6a6b11
Binary files /dev/null and b/e/eat-color differ
diff --git a/e/eat-mono b/e/eat-mono
new file mode 100644
index 0000000000..5d4b98b03a
Binary files /dev/null and b/e/eat-mono differ
diff --git a/e/eat-truecolor b/e/eat-truecolor
new file mode 100644
index 0000000000..c2c86b92d7
Binary files /dev/null and b/e/eat-truecolor differ
diff --git a/eat-tests.el b/eat-tests.el
new file mode 100644
index 0000000000..396504df03
--- /dev/null
+++ b/eat-tests.el
@@ -0,0 +1,6230 @@
+;;; eat-tests.el --- Tests for Eat -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Akib Azmain Turja.
+
+;; Author: Akib Azmain Turja <akib@disroot.org>
+;; Keywords: tests
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; For a full copy of the GNU General Public License
+;; see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file contains all tests for Eat.  This includes tests for the
+;; terminal emulator itself.
+
+;;; Code:
+
+(require 'ert)
+(require 'eat)
+(require 'cl-lib)
+
+
+;;;; Helpers.
+
+(defun eat--tests-parse-text-properties (string)
+  "Parse and modify the text properties of STRING.
+
+Modify the text properties of STRING so that for two strings with
+identical contents and similar appearance `equal-including-properties'
+will return t."
+  (let ((pos 0))
+    (while (< pos (length string))
+      (let ((next-pos (or (next-single-property-change
+                           pos 'face string)
+                          (length string)))
+            (face (get-text-property pos 'face string)))
+        (set-text-properties
+         pos next-pos
+         `( :foreground ,(plist-get face :foreground)
+            :background ,(plist-get face :background)
+            :underline-type ,(plist-get (plist-get face :underline)
+                                        :style)
+            :underline-color ,(plist-get (plist-get face :underline)
+                                         :color)
+            :crossed ,(plist-get face :strike-through)
+            :intensity ,(let ((list (plist-get face :inherit)))
+                          (cond ((member 'eat-term-faint list) 'faint)
+                                ((member 'eat-term-bold list) 'bold)))
+            :italic ,(not (not (member 'eat-term-italic
+                                       (plist-get face :inherit))))
+            :blink ,(let ((list (plist-get face :inherit)))
+                      (cond
+                       ((member 'eat-term-slow-blink list) 'slow)
+                       ((member 'eat-term-fast-blink list) 'fast)))
+            :font ,(let ((list (plist-get face :inherit)))
+                     (cond ((member 'eat-term-font-0 list) 0)
+                           ((member 'eat-term-font-1 list) 1)
+                           ((member 'eat-term-font-2 list) 2)
+                           ((member 'eat-term-font-3 list) 3)
+                           ((member 'eat-term-font-4 list) 4)
+                           ((member 'eat-term-font-5 list) 5)
+                           ((member 'eat-term-font-6 list) 6)
+                           ((member 'eat-term-font-7 list) 7)
+                           ((member 'eat-term-font-8 list) 8)
+                           ((member 'eat-term-font-9 list) 9)
+                           (t 0))))
+         string)
+        (setq pos next-pos)))
+    string))
+
+(defun eat--tests-sanitize-expected-text (string)
+  "Sanitize the text properties of expected string STRING."
+  (let ((pos 0))
+    (while (< pos (length string))
+      (let ((next-pos (or (next-property-change pos string)
+                          (length string))))
+        (set-text-properties
+         pos next-pos
+         (mapcan
+          (lambda (prop)
+            (list (car prop)
+                  (or (get-text-property pos (car prop) string)
+                      (cdr prop))))
+          '((:foreground . nil)
+            (:background . nil)
+            (:underline-type . nil)
+            (:underline-color . nil)
+            (:crossed . nil)
+            (:intensity . nil)
+            (:italic . nil)
+            (:blink . nil)
+            (:font . 0)))
+         string)
+        (setq pos next-pos)))
+    string))
+
+(defun eat--tests-compare-lines (actual expected)
+  "Compare ACTUAL and EXPECTED."
+  (let ((a (eat--tests-parse-text-properties actual))
+        (b (eat--tests-sanitize-expected-text expected)))
+    (cl-flet
+        ((visually-equal (a b)
+           (if (> emacs-major-version 28)
+               (should (equal-including-properties a b))
+             ;; On Emacs versions less than 29,
+             ;; `equal-including-properties' returns t only if the
+             ;; properties of a and b are `eq', so we compare the
+             ;; strings ourselves.
+             (and
+              (should (string= a b))
+              (cl-every
+               (lambda (i)
+                 (cl-flet ((plist-to-alist (plist)
+                             (let ((alist nil))
+                               (while plist
+                                 (push (cons (pop plist)
+                                             (pop plist))
+                                       alist))
+                               (sort
+                                alist
+                                (lambda (a b)
+                                  (string<
+                                   (symbol-name (car a))
+                                   (symbol-name (car b))))))))
+                   (should
+                    (equal
+                     (plist-to-alist (text-properties-at i a))
+                     (plist-to-alist (text-properties-at i b))))))
+               (number-sequence 0 (1- (length a))))))))
+      (cond ((= (length a) (length b))
+             (visually-equal a b))
+            ((< (length a) (length b))
+             (and (visually-equal
+                   a (substring b 0 (length a)))
+                  (let ((str (substring b (length a))))
+                    (and (string-blank-p str)
+                         (visually-equal
+                          str (eat--tests-parse-text-properties
+                               (substring-no-properties str)))))))
+            ((> (length a) (length b))
+             (and (visually-equal
+                   (substring a 0 (length b)) b)
+                  (let ((str (substring a (length b))))
+                    (and (string-blank-p str)
+                         (visually-equal
+                          str (eat--tests-parse-text-properties
+                               (substring-no-properties str)))))))))))
+
+(defun eat--tests-compare-scrollback (terminal lines)
+  "Compare TERMINAL's scrollback buffer with LINES."
+  (let ((scrollback
+         (nbutlast
+          (split-string
+           (buffer-substring
+            (eat-term-beginning terminal)
+            (eat-term-display-beginning terminal))
+           "\n" nil nil))))
+    (and (should
+          (or (= (eat-term-display-beginning terminal)
+                 (eat-term-beginning terminal))
+              (= (char-before (eat-term-display-beginning terminal))
+                 ?\n)))
+         (should (= (length scrollback) (length lines)))
+         (cl-every (lambda (pair)
+                     (eat--tests-compare-lines
+                      (car pair) (cdr pair)))
+                   (cl-mapcar #'cons scrollback lines)))))
+
+(defun eat--tests-compare-display (terminal lines)
+  "Compare TERMINAL's scrollback buffer with LINES."
+  (let ((display
+         (split-string
+          (buffer-substring
+           (eat-term-display-beginning terminal)
+           (eat-term-end terminal))
+          "\n" nil nil)))
+    (and (should (<= (length display) (cdr (eat-term-size terminal))))
+         (cl-every
+          (lambda (i)
+            (let ((actual (or (nth i display) ""))
+                  (expected (or (nth i lines) "")))
+              (and (<= (length actual) (car (eat-term-size terminal)))
+                   (eat--tests-compare-lines actual expected))))
+          (number-sequence 0 (1- (cdr (eat-term-size terminal))))))))
+
+(defun eat--tests-compare-cursor-pos (terminal cursor-pos)
+  "Compare TERMINAL's cursor position with CURSOR-POS.
+
+CURSOR-POS should be a cons cell of form (Y . X)."
+  (let* ((prev-lines (split-string
+                      (buffer-substring
+                       (eat-term-display-beginning terminal)
+                       (eat-term-display-cursor terminal))
+                      "\n" nil nil))
+         (y (length prev-lines))
+         (x (1+ (length (car (last prev-lines))))))
+    (should (= (car cursor-pos) y))
+    (should (= (cdr cursor-pos) x))))
+
+(defun eat--tests-add-properties (string &rest intervals)
+  "Add properties to STRING according to INTERVALS.
+
+INTERVALS is a list.  Each element of it is a list of form
+\((BEGIN . END) PLIST...).  For each element in INTERVALS, add PLIST
+to string from BEGIN to END."
+  (dolist (interval intervals)
+    (set-text-properties (caar interval) (cdar interval)
+                         (cdr interval) string))
+  string)
+
+(defmacro eat--tests-with-term (spec &rest body)
+  "Make a temporary terminal with SPEC and run BODY with it.
+
+SPEC is a form that should evaluate to a plist.  The plist can have
+any of the following properties:
+
+  `:width'        Width of terminal.  Defaults to 20.
+  `:height'       Height of terminal.  Defaults to 6.
+
+The following functions are available within BODY:
+
+(terminal)
+  Return the terminal.
+
+(output &rest ARGS)
+  Output ARGS to the terminal, where ARGS is a list of string.
+
+(input-event EVENT &optional REF-POS N)
+  Input EVENT to the terminal.  REF-POS is the starting position of
+  the terminal, a mouse position list.  N is how times to input EVENT.
+
+(input)
+  Return all unread input.
+
+(should-term SCROLLBACK DISPLAY CURSOR)
+  Match the terminal with SCROLLBACK, DISPLAY and CURSOR.  SCROLLBACK
+  is expected content of scrollback region.  DISPLAY is the expected
+  display.  CURSOR is the expected cursor position, as a cons (X . Y),
+  where X and Y are one-based.
+
+  Both SCROLLBACK and DISPLAY are list of strings.  They matched with
+  the terminal for visual equivalence, not literal equivaence (i.e,
+  properties are also compared, and \"foo\" and \"foo   \" are assumed
+  to be equivalent).
+
+(add-props STRING &rest INTERVALS)
+  Add text properties to STRING as specified in INTERVALS.  Each
+  argument in INTERVALS is of form ((BEGIN . END) PROPERTY VALUE
+  PROPERTY VALUE...).  Here is all PROPERTY is applied on STRING from
+  BEGIN to END.  PROPERTY should one of `:foreground', `:background'
+  `:underline-type', `:underline-color', `:crossed', `:intensity',
+  `:italic', `:blink' and `:font'.  Any other properties are also
+  applied but ignored by `should-term'."
+  (declare (indent 1))
+  (let ((term (make-symbol "term"))
+        (input (make-symbol "input")))
+    `(with-temp-buffer
+       (let ((,term (eat-term-make (current-buffer) (point)))
+             (,input ""))
+         (unwind-protect
+             (progn
+               (cl-destructuring-bind
+                   (&key (width 20) (height 6)) ,spec
+                 (eat-term-resize ,term width height))
+               (setf (eat-term-input-function ,term)
+                     (lambda (_ str)
+                       (setq ,input (concat ,input str))))
+               (cl-labels
+                   ((terminal ()
+                      ,term)
+                    (output (&rest args)
+                      (dolist (str args)
+                        (eat-term-process-output ,term str))
+                      (eat-term-redisplay ,term))
+                    (input-event (event &optional ref-pos n)
+                      (eat-term-input-event ,term n event ref-pos))
+                    (input ()
+                      (prog1 ,input
+                        (setq ,input "")))
+                    (should-term (&key scrollback display cursor)
+                      (eat--tests-compare-scrollback ,term scrollback)
+                      (eat--tests-compare-display ,term display)
+                      (eat--tests-compare-cursor-pos ,term cursor))
+                    (add-props (str &rest intervals)
+                      (apply #'eat--tests-add-properties
+                             str intervals)))
+                 ,@body))
+           (eat-term-delete ,term))))))
+
+
+;;;; Tests.
+
+;;;;; Text Writing and Insertion Tests.
+
+(ert-deftest eat-test-plain-text ()
+  "Test plain text handling.
+
+Send only plain text (i.e. no control sequences, not even newline) and
+compare the output with the expected output.  Don't do test automatic
+margin."
+  (eat--tests-with-term '()
+    (output "some test string")
+    (should-term :display '("some test string    ")
+                 :cursor '(1 . 17))))
+
+(ert-deftest eat-test-auto-margin ()
+  "Test automatic margin and toggling it."
+  (eat--tests-with-term '()
+    (should-term :cursor '(1 . 1))
+    ;; Default: Automatic margin enabled.
+    (output "some test string... and some more")
+    (should-term :display '("some test string..."
+                            "and some more")
+                 :cursor '(2 . 14))
+    ;; Automatic margin disabled.
+    (output "\n\e[?7lsome test string... and some more")
+    (should-term :display '("some test string..."
+                            "and some more"
+                            "some test string...e")
+                 :cursor '(3 . 20))
+    ;; Automatic margin enabled.
+    (output "\n\e[?7hsome test string... and some more")
+    (should-term :display '("some test string..."
+                            "and some more"
+                            "some test string...e"
+                            "some test string..."
+                            "and some more")
+                 :cursor '(5 . 14))))
+
+(ert-deftest eat-test-insert-mode ()
+  "Test automatic margin and toggling it."
+  (eat--tests-with-term '()
+    ;; Default: Insert mode disabled.
+    (output "a\bb")
+    (should-term :display '("b")
+                 :cursor '(1 . 2))
+    ;; Insert mode enabled.
+    (output "\e[4hb\ba")
+    (should-term :display '("bab")
+                 :cursor '(1 . 3))
+    ;; Insert mode disabled.
+    (output "\e[4lc\by")
+    (should-term :display '("bay")
+                 :cursor '(1 . 4))))
+
+
+;;;;; Cursor Motion Tests.
+
+(ert-deftest eat-test-character-tabulation ()
+  "Test character tabulation control function."
+  (eat--tests-with-term '()
+    (output "\t")
+    (should-term :cursor '(1 . 9))
+    (output "\t")
+    (should-term :cursor '(1 . 17))
+    (output "\t")
+    (should-term :cursor '(1 . 20))
+    (output "\n ")
+    (should-term :cursor '(2 . 2))
+    (output "\t")
+    (should-term :cursor '(2 . 9))))
+
+(ert-deftest eat-test-cursor-backward-tabulation ()
+  "Test cursor backward tabulation control function."
+  (eat--tests-with-term '()
+    (output "\t")
+    (should-term :cursor '(1 . 9))
+    (output "\t")
+    (should-term :cursor '(1 . 17))
+    (output "\t")
+    (should-term :cursor '(1 . 20))
+    (output "\n ")
+    (should-term :cursor '(2 . 2))
+    (output "\t")
+    (should-term :cursor '(2 . 9))))
+
+(ert-deftest eat-test-line-tabulation ()
+  "Test line tabulation control function."
+  (eat--tests-with-term '()
+    (output "\v")
+    (should-term :cursor '(2 . 1))
+    (output "  ")
+    (should-term :cursor '(2 . 3))
+    (output "\v")
+    (should-term :cursor '(3 . 3))
+    (output "\v\v\v")
+    (should-term :cursor '(6 . 3))
+    (output "\v")
+    (should-term :scrollback '("")
+                 :cursor '(6 . 3))))
+
+(ert-deftest eat-test-form-feed ()
+  "Test form feed."
+  (eat--tests-with-term '()
+    (output "\f")
+    (should-term :cursor '(2 . 1))
+    (output "  ")
+    (should-term :cursor '(2 . 3))
+    (output "\f")
+    (should-term :cursor '(3 . 3))
+    (output "\f\f\f")
+    (should-term :cursor '(6 . 3))
+    (output "\f")
+    (should-term :scrollback '("")
+                 :cursor '(6 . 3))))
+
+(ert-deftest eat-test-line-feed ()
+  "Test line feed control function."
+  (eat--tests-with-term '()
+    (output "\n")
+    (should-term :cursor '(2 . 1))
+    (output "    \n")
+    (should-term :cursor '(3 . 1))
+    (output "\eE")
+    (should-term :cursor '(4 . 1))
+    (output "    \eE")
+    (should-term :cursor '(5 . 1))))
+
+(ert-deftest eat-test-index ()
+  "Test index control function."
+  (eat--tests-with-term '()
+    (output "\eD")
+    (should-term :cursor '(2 . 1))
+    (output "    \eD")
+    (should-term :cursor '(3 . 5))
+    (output "\eD")
+    (should-term :cursor '(4 . 5))
+    (output "    \eD")
+    (should-term :cursor '(5 . 9))))
+
+(ert-deftest eat-test-reverse-index ()
+  "Test reverse index control function.
+
+Use newlines to move to an initial position from where the control
+function is to be invoked."
+  (eat--tests-with-term '()
+    (output "\n\n")
+    (should-term :cursor '(3 . 1))
+    (output "\eM")
+    (should-term :cursor '(2 . 1))
+    (output "    \eM")
+    (should-term :cursor '(1 . 5))))
+
+(ert-deftest eat-test-backspace ()
+  "Test backspace control function.
+
+Use spaces to move to an initial position from where the control
+function is to be invoked."
+  (eat--tests-with-term '()
+    (output " ")
+    (should-term :cursor '(1 . 2))
+    (output "\b")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-carriage-return ()
+  "Test carriage return control function.
+
+Use spaces to move to an initial position from where the control
+function is to be invoked."
+  (eat--tests-with-term '()
+    (output "\r")
+    (should-term :cursor '(1 . 1))
+    (output "    ")
+    (should-term :cursor '(1 . 5))
+    (output "\r")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-cursor-right ()
+  "Test cursor right control function."
+  (eat--tests-with-term '()
+    (output "\e[C")
+    (should-term :cursor '(1 . 2))
+    (output "\e[0C")
+    (should-term :cursor '(1 . 3))
+    (output "\e[5C")
+    (should-term :cursor '(1 . 8))
+    (output "\e[20C")
+    (should-term :cursor '(1 . 20))))
+
+(ert-deftest eat-test-cursor-left ()
+  "Test cursor up control function.
+
+Use spaces to move to an initial position from where the control
+function is to be invoked."
+  (eat--tests-with-term '()
+    (output "                ")
+    (should-term :cursor '(1 . 17))
+    (output "\e[D")
+    (should-term :cursor '(1 . 16))
+    (output "\e[0D")
+    (should-term :cursor '(1 . 15))
+    (output "\e[7D")
+    (should-term :cursor '(1 . 8))
+    (output "\e[10D")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-cursor-down ()
+  "Test cursor down control function."
+  (eat--tests-with-term '()
+    (output "\e[B")
+    (should-term :cursor '(2 . 1))
+    (output "\e[0B")
+    (should-term :cursor '(3 . 1))
+    (output "    ")
+    (should-term :cursor '(3 . 5))
+    (output "\e[6B")
+    (should-term :cursor '(6 . 5))))
+
+(ert-deftest eat-test-cursor-up ()
+  "Test cursor up control function.
+
+Use spaces and newlines to move to an initial position from where the
+control function is to be invoked."
+  (eat--tests-with-term '()
+    (output "\n\n\n\n\n")
+    (should-term :cursor '(6 . 1))
+    (output "\e[A")
+    (should-term :cursor '(5 . 1))
+    (output "\e[0A")
+    (should-term :cursor '(4 . 1))
+    (output "    ")
+    (should-term :cursor '(4 . 5))
+    (output "\e[2A")
+    (should-term :cursor '(2 . 5))
+    (output "\e[4A")
+    (should-term :cursor '(1 . 5))))
+
+(ert-deftest eat-test-cursor-next-line ()
+  "Test cursor next line control function."
+  (eat--tests-with-term '(:height 10)
+    (output "\e[F")
+    (should-term :cursor '(2 . 1))
+    (output "\e[0F")
+    (should-term :cursor '(3 . 1))
+    (output "\e[2F")
+    (should-term :cursor '(5 . 1))
+    (output "    \e[F")
+    (should-term :cursor '(6 . 1))
+    (output "        \e[0F")
+    (should-term :cursor '(7 . 1))
+    (output "  \e[3F")
+    (should-term :cursor '(10 . 1))
+    (output "   \e[F")
+    (should-term :cursor '(10 . 1))))
+
+(ert-deftest eat-test-cursor-previous-line ()
+  "Test cursor previous line control function.
+
+Use newlines to move to an initial position from where the control
+function is to be invoked."
+  (eat--tests-with-term '(:height 10)
+    (output "\n\n\n\n\n\n\n\n\n")
+    (should-term :cursor '(10 . 1))
+    (output "\e[E")
+    (should-term :cursor '(9 . 1))
+    (output "\e[0E")
+    (should-term :cursor '(8 . 1))
+    (output "\e[2E")
+    (should-term :cursor '(6 . 1))
+    (output "    \e[E")
+    (should-term :cursor '(5 . 1))
+    (output "        \e[0E")
+    (should-term :cursor '(4 . 1))
+    (output "  \e[3E")
+    (should-term :cursor '(1 . 1))
+    (output "   \e[E")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-cursor-character-absolute ()
+  "Test cursor character absolute control function."
+  (eat--tests-with-term '()
+    (output "\e[5G")
+    (should-term :cursor '(1 . 5))
+    (output "\e[0G")
+    (should-term :cursor '(1 . 1))
+    (output "\e[15G")
+    (should-term :cursor '(1 . 15))
+    (output "\e[G")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-character-position-absolute ()
+  "Test character position absolute control function."
+  (eat--tests-with-term '()
+    (output "\e[5`")
+    (should-term :cursor '(1 . 5))
+    (output "\e[0`")
+    (should-term :cursor '(1 . 1))
+    (output "\e[15`")
+    (should-term :cursor '(1 . 15))
+    (output "\e[`")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-line-position-absolute ()
+  "Test line position absolute control function."
+  (eat--tests-with-term '()
+    (output "\e[2d")
+    (should-term :cursor '(2 . 1))
+    (output "\e[0d")
+    (should-term :cursor '(1 . 1))
+    (output "\e[5d")
+    (should-term :cursor '(5 . 1))
+    (output "\e[d")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-cursor-position ()
+  "Test cursor position control function."
+  (eat--tests-with-term '()
+    (output "\e[2;2H")
+    (should-term :cursor '(2 . 2))
+    (output "\e[;5H")
+    (should-term :cursor '(1 . 5))
+    (output "\e[4;H")
+    (should-term :cursor '(4 . 1))
+    (output "\e[7;H")
+    (should-term :cursor '(6 . 1))
+    (output "\e[0;0H")
+    (should-term :cursor '(1 . 1))
+    (output "\e[;30H")
+    (should-term :cursor '(1 . 20))
+    (output "\e[10;25H")
+    (should-term :cursor '(6 . 20))
+    (output "\e[H")
+    (should-term :cursor '(1 . 1))))
+
+(ert-deftest eat-test-character-and-line-position ()
+  "Test character and line position control function."
+  (eat--tests-with-term '()
+    (output "\e[2;2f")
+    (should-term :cursor '(2 . 2))
+    (output "\e[;5f")
+    (should-term :cursor '(1 . 5))
+    (output "\e[4;f")
+    (should-term :cursor '(4 . 1))
+    (output "\e[7;f")
+    (should-term :cursor '(6 . 1))
+    (output "\e[0;0f")
+    (should-term :cursor '(1 . 1))
+    (output "\e[;30f")
+    (should-term :cursor '(1 . 20))
+    (output "\e[10;25f")
+    (should-term :cursor '(6 . 20))
+    (output "\e[f")
+    (should-term :cursor '(1 . 1))))
+
+
+;;;;; Scrolling Tests.
+
+(ert-deftest eat-test-scroll-up ()
+  "Test scroll up control function."
+  (eat--tests-with-term '()
+    (output "some test string...\nmore, more...\n"
+            "more, more, more...\nand some more")
+    (should-term :display '("some test string..."
+                            "more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[S")
+    (should-term :scrollback '("some test string...")
+                 :display '("more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[0S")
+    (should-term :scrollback '("some test string...")
+                 :display '("more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[2S")
+    (should-term :scrollback '("some test string..."
+                               "more, more..."
+                               "more, more, more...")
+                 :display '("and some more")
+                 :cursor '(4 . 14))
+    (output "\nnew line 1\nnew line 2\nnew line 3\n"
+            "new line 4\nnew line 5\nnew line 6\e[2;4r")
+    (should-term :scrollback '("some test string..."
+                               "more, more..."
+                               "more, more, more..."
+                               "and some more"
+                               ""
+                               ""
+                               "")
+                 :display '("new line 1"
+                            "new line 2"
+                            "new line 3"
+                            "new line 4"
+                            "new line 5"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[S")
+    (should-term :scrollback '("some test string..."
+                               "more, more..."
+                               "more, more, more..."
+                               "and some more"
+                               ""
+                               ""
+                               "")
+                 :display '("new line 1"
+                            "new line 3"
+                            "new line 4"
+                            ""
+                            "new line 5"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[0S")
+    (should-term :scrollback '("some test string..."
+                               "more, more..."
+                               "more, more, more..."
+                               "and some more"
+                               ""
+                               ""
+                               "")
+                 :display '("new line 1"
+                            "new line 3"
+                            "new line 4"
+                            ""
+                            "new line 5"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[2S")
+    (should-term :scrollback '("some test string..."
+                               "more, more..."
+                               "more, more, more..."
+                               "and some more"
+                               ""
+                               ""
+                               "")
+                 :display '("new line 1"
+                            ""
+                            ""
+                            ""
+                            "new line 5"
+                            "new line 6")
+                 :cursor '(1 . 1))))
+
+(ert-deftest eat-test-scroll-down ()
+  "Test scroll down control function."
+  (eat--tests-with-term '()
+    (output "some test string...\nmore, more...\n"
+            "more, more, more...\nand some more")
+    (should-term :display '("some test string..."
+                            "more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[T")
+    (should-term :display '(""
+                            "some test string..."
+                            "more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[0T")
+    (should-term :display '(""
+                            "some test string..."
+                            "more, more..."
+                            "more, more, more..."
+                            "and some more")
+                 :cursor '(4 . 14))
+    (output "\e[2T")
+    (should-term :display '(""
+                            ""
+                            ""
+                            "some test string..."
+                            "more, more..."
+                            "more, more, more...")
+                 :cursor '(4 . 14))
+    (output "\n\n\nnew line 1\nnew line 2\nnew line 3\n"
+            "new line 4\nnew line 5\nnew line 6\e[2;5r")
+    (should-term :scrollback '(""
+                               ""
+                               ""
+                               "some test string..."
+                               "more, more..."
+                               "more, more, more...")
+                 :display '("new line 1"
+                            "new line 2"
+                            "new line 3"
+                            "new line 4"
+                            "new line 5"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[T")
+    (should-term :scrollback '(""
+                               ""
+                               ""
+                               "some test string..."
+                               "more, more..."
+                               "more, more, more...")
+                 :display '("new line 1"
+                            ""
+                            "new line 2"
+                            "new line 3"
+                            "new line 4"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[0T")
+    (should-term :scrollback '(""
+                               ""
+                               ""
+                               "some test string..."
+                               "more, more..."
+                               "more, more, more...")
+                 :display '("new line 1"
+                            ""
+                            "new line 2"
+                            "new line 3"
+                            "new line 4"
+                            "new line 6")
+                 :cursor '(1 . 1))
+    (output "\e[2T")
+    (should-term :scrollback '(""
+                               ""
+                               ""
+                               "some test string..."
+                               "more, more..."
+                               "more, more, more...")
+                 :display '("new line 1"
+                            ""
+                            ""
+                            ""
+                            "new line 2"
+                            "new line 6")
+                 :cursor '(1 . 1))))
+
+(ert-deftest eat-test-auto-scrolling ()
+  "Test automatic scrolling when cursor reaches end of display.
+
+Test with every control functions and text combination that trigger
+automatic scrolling as a side effect."
+  (eat--tests-with-term '()
+    ;; Test with newlines.
+    (output "some test string...\n\n\n\n\n\nand some more")
+    (should-term :scrollback '("some test string...")
+                 :display '(""
+                            ""
+                            ""
+                            ""
+                            ""
+                            "and some more")
+                 :cursor '(6 . 14))
+    ;; Test with automatic margin.
+    (output "...more, more, stop.")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '(""
+                            ""
+                            ""
+                            ""
+                            "and some more...more"
+                            ", more, stop.")
+                 :cursor '(6 . 14))
+    ;; Test with reverse index.
+    (output "\eM\eM\eM\eM\eM\eM")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '(""
+                            ""
+                            ""
+                            ""
+                            ""
+                            "and some more...more")
+                 :cursor '(1 . 14))
+    ;; Test with newlines and scroll region.
+    (output "\e[2;5rline 1\nline 2\nline 3\nline 4\nline 5")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '("line 1"
+                            "line 2"
+                            "line 3"
+                            "line 4"
+                            "line 5"
+                            "and some more...more")
+                 :cursor '(5 . 7))
+    (output "\n")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '("line 1"
+                            "line 3"
+                            "line 4"
+                            "line 5"
+                            ""
+                            "and some more...more")
+                 :cursor '(5 . 1))
+    ;; Test with automatic margin and scroll region.
+    (output "...more content, more, stop.")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '("line 1"
+                            "line 4"
+                            "line 5"
+                            "...more content, mor"
+                            "e, stop."
+                            "and some more...more")
+                 :cursor '(5 . 9))
+    ;; Test with reverse index and scroll region.
+    (output "\eM\eM\eM\eM\eM")
+    (should-term :scrollback '("some test string..."
+                               "")
+                 :display '("line 1"
+                            ""
+                            ""
+                            "line 4"
+                            "line 5"
+                            "and some more...more")
+                 :cursor '(2 . 9))))
+
+
+;;;;; SGR Tests.
+
+;; Beware, this section is a nightware of code repetition.
+
+(ert-deftest eat-test-sgr-foreground ()
+  "Test SGR foreground color.  Test 256 colors and 24-bit colors."
+  (eat--tests-with-term '()
+    ;; ANSI colors.
+    (output "\e[31mred\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(2 . 1))
+    (output "\e[32mgreen\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(3 . 1))
+    (output "\e[37mwhite\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t))))
+     :cursor '(4 . 1))
+    (output "\e[30mblack\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 1))
+    ;; ANSI bright colors.
+    (output "\e[91mbright red\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[92mbright green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t))))
+     :display `(,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[97mbright white\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t))))
+     :display `(,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[90mbright black\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t))))
+     :display `(,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(6 . 1))
+    ;; ANSI colors using 256-color sequence.
+    (output "\e[38;5;1mred\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t))))
+     :display `(,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;2mgreen\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t))))
+     :display `(,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;7mwhite\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t))))
+     :display `(,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;0mblack\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t))))
+     :display `(,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(6 . 1))
+    ;; ANSI bright colors using 256-color sequence.
+    (output "\e[38;5;9mbright red\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t))))
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;10mbright green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t))))
+     :display `(,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;15mbright white\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t))))
+     :display `(,(add-props
+                  "white"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;8mbright black\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t))))
+     :display `(,(add-props
+                  "black"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(6 . 1))
+    ;; 256-color.
+    (output "\e[38;5;119mcolor-119\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t))))
+     :display `(,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-119 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[38;5;255mcolor-255\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t))))
+     :display `(,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-255 nil t))))
+     :cursor '(6 . 1))
+    ;; 24-bit color (truecolor).
+    (output "\e[38;2;34;139;34mforest green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t))))
+     :display `(,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :foreground "#228b22")))
+     :cursor '(6 . 1))
+    (output "\e[38;2;160;32;240mpurple\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t))))
+     :display `(,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :foreground "#228b22"))
+                ,(add-props
+                  "purple"
+                  '((0 . 6)
+                    :foreground "#a020f0")))
+     :cursor '(6 . 1))
+    (output "\e[39mdefault\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :foreground ,(face-foreground
+                                     'eat-term-color-8 nil t))))
+     :display `(,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :foreground "#228b22"))
+                ,(add-props
+                  "purple"
+                  '((0 . 6)
+                    :foreground "#a020f0"))
+                "default")
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-background ()
+  "Test SGR background color.  Test 256 colors and 24-bit colors."
+  (eat--tests-with-term '()
+    ;; ANSI colors.
+    (output "\e[41mred\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(2 . 1))
+    (output "\e[42mgreen\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(3 . 1))
+    (output "\e[47mwhite\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t))))
+     :cursor '(4 . 1))
+    (output "\e[40mblack\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 1))
+    ;; ANSI bright colors.
+    (output "\e[101mbright red\n")
+    (should-term
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[102mbright green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t))))
+     :display `(,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[107mbright white\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t))))
+     :display `(,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[100mbright black\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t))))
+     :display `(,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(6 . 1))
+    ;; ANSI colors using 256-color sequence.
+    (output "\e[48;5;1mred\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t))))
+     :display `(,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;2mgreen\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t))))
+     :display `(,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;7mwhite\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t))))
+     :display `(,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;0mblack\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t))))
+     :display `(,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(6 . 1))
+    ;; ANSI bright colors using 256-color sequence.
+    (output "\e[48;5;9mbright red\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t))))
+     :display `(,(add-props
+                  "red"
+                  `((0 . 3)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;10mbright green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t))))
+     :display `(,(add-props
+                  "green"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;15mbright white\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t))))
+     :display `(,(add-props
+                  "white"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;8mbright black\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t))))
+     :display `(,(add-props
+                  "black"
+                  `((0 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t)))
+                ,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(6 . 1))
+    ;; 256-color.
+    (output "\e[48;5;119mcolor-119\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t))))
+     :display `(,(add-props
+                  "bright red"
+                  `((0 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-9 nil t)))
+                ,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-119 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[48;5;255mcolor-255\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t))))
+     :display `(,(add-props
+                  "bright green"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-10 nil t)))
+                ,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-255 nil t))))
+     :cursor '(6 . 1))
+    ;; 24-bit color (truecolor).
+    (output "\e[48;2;34;139;34mforest green\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t))))
+     :display `(,(add-props
+                  "bright white"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t)))
+                ,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :background "#228b22")))
+     :cursor '(6 . 1))
+    (output "\e[48;2;160;32;240mpurple\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t))))
+     :display `(,(add-props
+                  "bright black"
+                  `((0 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :background "#228b22"))
+                ,(add-props
+                  "purple"
+                  '((0 . 6)
+                    :background "#a020f0")))
+     :cursor '(6 . 1))
+    (output "\e[49mdefault\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t)))
+                   ,(add-props
+                     "red"
+                     `((0 . 3)
+                       :background ,(face-foreground
+                                     'eat-term-color-1 nil t)))
+                   ,(add-props
+                     "green"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-2 nil t)))
+                   ,(add-props
+                     "white"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-7 nil t)))
+                   ,(add-props
+                     "black"
+                     `((0 . 5)
+                       :background ,(face-foreground
+                                     'eat-term-color-0 nil t)))
+                   ,(add-props
+                     "bright red"
+                     `((0 . 10)
+                       :background ,(face-foreground
+                                     'eat-term-color-9 nil t)))
+                   ,(add-props
+                     "bright green"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-10 nil t)))
+                   ,(add-props
+                     "bright white"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-15 nil t)))
+                   ,(add-props
+                     "bright black"
+                     `((0 . 12)
+                       :background ,(face-foreground
+                                     'eat-term-color-8 nil t))))
+     :display `(,(add-props
+                  "color-119"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-119 nil t)))
+                ,(add-props
+                  "color-255"
+                  `((0 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-255 nil t)))
+                ,(add-props
+                  "forest green"
+                  '((0 . 12)
+                    :background "#228b22"))
+                ,(add-props
+                  "purple"
+                  '((0 . 6)
+                    :background "#a020f0"))
+                "default")
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-intensity ()
+  "Test SGR intensity attributes (both bold and faint)."
+  (eat--tests-with-term '()
+    (output "\e[1mbold\n")
+    (should-term
+     :display `(,(add-props "bold" `((0 . 4)
+                                     :intensity bold)))
+     :cursor '(2 . 1))
+    (output "\e[2mfaint\n")
+    (should-term
+     :display `(,(add-props "bold" `((0 . 4)
+                                     :intensity bold))
+                ,(add-props "faint" `((0 . 5)
+                                      :intensity faint)))
+     :cursor '(3 . 1))
+    (output "\e[22mnormal\n")
+    (should-term
+     :display `(,(add-props "bold" `((0 . 4)
+                                     :intensity bold))
+                ,(add-props "faint" `((0 . 5)
+                                      :intensity faint))
+                "normal")
+     :cursor '(4 . 1))))
+
+(ert-deftest eat-test-sgr-italic ()
+  "Test SGR italic attribute."
+  (eat--tests-with-term '()
+    (output "\e[3mitalic\n")
+    (should-term
+     :display `(,(add-props "italic" `((0 . 6) :italic t)))
+     :cursor '(2 . 1))
+    (output "\e[23mnormal\n")
+    (should-term
+     :display `(,(add-props "italic" `((0 . 6) :italic t))
+                "normal")
+     :cursor '(3 . 1))))
+
+(ert-deftest eat-test-sgr-underline ()
+  "Test SGR underline with no color, 256 colors and 24-bit colors."
+  (eat--tests-with-term '()
+    ;; Without colors.
+    (output "\e[4mdefault line\n")
+    (should-term
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line)))
+     :cursor '(2 . 1))
+    (output "\e[4:0mnormal\n")
+    (should-term
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                "normal")
+     :cursor '(3 . 1))
+    (output "\e[4:1mdefault line\n")
+    (should-term
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                "normal"
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line)))
+     :cursor '(4 . 1))
+    (output "\e[4:2mdefault line\n")
+    (should-term
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                "normal"
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line)))
+     :cursor '(5 . 1))
+    (output "\e[4:3mdefault wave\n")
+    (should-term
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                "normal"
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave)))
+     :cursor '(6 . 1))
+    (output "\e[4:4mdefault wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line)))
+     :display `("normal"
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave)))
+     :cursor '(6 . 1))
+    (output "\e[4:5mdefault wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal")
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave)))
+     :cursor '(6 . 1))
+    (output "\e[4;58;5;6mcyan line\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line)))
+     :display `(,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "cyan line"
+                  `((0 . 9)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-6 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[4:3;58;5;3myellow wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line)))
+     :display `(,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "cyan line"
+                  `((0 . 9)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-6 nil t)))
+                ,(add-props
+                  "yellow wave"
+                  `((0 . 11)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-3 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[4:1;58;5;13mbright magenta line\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave)))
+     :display `(,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "cyan line"
+                  `((0 . 9)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-6 nil t)))
+                ,(add-props
+                  "yellow wave"
+                  `((0 . 11)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-3 nil t)))
+                ,(add-props
+                  "bright magenta line"
+                  `((0 . 19)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-13 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[4:4;58;5;133mcolor-133 wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave)))
+     :display `(,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "cyan line"
+                  `((0 . 9)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-6 nil t)))
+                ,(add-props
+                  "yellow wave"
+                  `((0 . 11)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-3 nil t)))
+                ,(add-props
+                  "bright magenta line"
+                  `((0 . 19)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-13 nil t)))
+                ,(add-props
+                  "color-133 wave"
+                  `((0 . 14)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-133 nil t))))
+     :cursor '(6 . 1))
+    (output "\e[4:2;58;2;160;32;240mpurple line\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave)))
+     :display `(,(add-props
+                  "cyan line"
+                  `((0 . 9)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-6 nil t)))
+                ,(add-props
+                  "yellow wave"
+                  `((0 . 11)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-3 nil t)))
+                ,(add-props
+                  "bright magenta line"
+                  `((0 . 19)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-13 nil t)))
+                ,(add-props
+                  "color-133 wave"
+                  `((0 . 14)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-133 nil t)))
+                ,(add-props
+                  "purple line"
+                  '((0 . 11)
+                    :underline-type line
+                    :underline-color "#a020f0")))
+     :cursor '(6 . 1))
+    (output "\e[4:5;58;2;0;0;139mdark blue wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "cyan line"
+                     `((0 . 9)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-6 nil t))))
+     :display `(,(add-props
+                  "yellow wave"
+                  `((0 . 11)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-3 nil t)))
+                ,(add-props
+                  "bright magenta line"
+                  `((0 . 19)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-13 nil t)))
+                ,(add-props
+                  "color-133 wave"
+                  `((0 . 14)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-133 nil t)))
+                ,(add-props
+                  "purple line"
+                  '((0 . 11)
+                    :underline-type line
+                    :underline-color "#a020f0"))
+                ,(add-props
+                  "dark blue wave"
+                  '((0 . 14)
+                    :underline-type wave
+                    :underline-color "#00008b")))
+     :cursor '(6 . 1))
+    (output "\e[59mdefault wave\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "cyan line"
+                     `((0 . 9)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-6 nil t)))
+                   ,(add-props
+                     "yellow wave"
+                     `((0 . 11)
+                       :underline-type wave
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-3 nil t))))
+     :display `(,(add-props
+                  "bright magenta line"
+                  `((0 . 19)
+                    :underline-type line
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-13 nil t)))
+                ,(add-props
+                  "color-133 wave"
+                  `((0 . 14)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-133 nil t)))
+                ,(add-props
+                  "purple line"
+                  '((0 . 11)
+                    :underline-type line
+                    :underline-color "#a020f0"))
+                ,(add-props
+                  "dark blue wave"
+                  '((0 . 14)
+                    :underline-type wave
+                    :underline-color "#00008b"))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave)))
+     :cursor '(6 . 1))
+    (output "\e[21mdefault line\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "cyan line"
+                     `((0 . 9)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-6 nil t)))
+                   ,(add-props
+                     "yellow wave"
+                     `((0 . 11)
+                       :underline-type wave
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-3 nil t)))
+                   ,(add-props
+                     "bright magenta line"
+                     `((0 . 19)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-13 nil t))))
+     :display `(,(add-props
+                  "color-133 wave"
+                  `((0 . 14)
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-133 nil t)))
+                ,(add-props
+                  "purple line"
+                  '((0 . 11)
+                    :underline-type line
+                    :underline-color "#a020f0"))
+                ,(add-props
+                  "dark blue wave"
+                  '((0 . 14)
+                    :underline-type wave
+                    :underline-color "#00008b"))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line)))
+     :cursor '(6 . 1))
+    (output "\e[24mnormal\n")
+    (should-term
+     :scrollback `(,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   "normal"
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default line"
+                     '((0 . 12)
+                       :underline-type line))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "default wave"
+                     '((0 . 12)
+                       :underline-type wave))
+                   ,(add-props
+                     "cyan line"
+                     `((0 . 9)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-6 nil t)))
+                   ,(add-props
+                     "yellow wave"
+                     `((0 . 11)
+                       :underline-type wave
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-3 nil t)))
+                   ,(add-props
+                     "bright magenta line"
+                     `((0 . 19)
+                       :underline-type line
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-13 nil t)))
+                   ,(add-props
+                     "color-133 wave"
+                     `((0 . 14)
+                       :underline-type wave
+                       :underline-color ,(face-foreground
+                                          'eat-term-color-133 nil t))))
+     :display `(,(add-props
+                  "purple line"
+                  '((0 . 11)
+                    :underline-type line
+                    :underline-color "#a020f0"))
+                ,(add-props
+                  "dark blue wave"
+                  '((0 . 14)
+                    :underline-type wave
+                    :underline-color "#00008b"))
+                ,(add-props
+                  "default wave"
+                  '((0 . 12)
+                    :underline-type wave))
+                ,(add-props
+                  "default line"
+                  '((0 . 12)
+                    :underline-type line))
+                "normal")
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-crossed ()
+  "Test SGR crossed attribute."
+  (eat--tests-with-term '()
+    (output "\e[9mcrossed\n")
+    (should-term
+     :display `(,(add-props "crossed" `((0 . 7) :crossed t)))
+     :cursor '(2 . 1))
+    (output "\e[29mnormal\n")
+    (should-term
+     :display `(,(add-props "crossed" `((0 . 7) :crossed t))
+                "normal")
+     :cursor '(3 . 1))))
+
+(ert-deftest eat-test-sgr-inverse ()
+  "Test SGR inverse attributes."
+  (eat--tests-with-term '()
+    (output "\e[7mdefault\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'default nil t))))
+     :cursor '(2 . 1))
+    (output "\e[31mred fg\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'default nil t)))
+                ,(add-props
+                  "red fg"
+                  `((0 . 6)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(3 . 1))
+    (output "\e[42mred fg green bg\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'default nil t)))
+                ,(add-props
+                  "red fg"
+                  `((0 . 6)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "red fg green bg"
+                  `((0 . 15)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(4 . 1))
+    (output "\e[39mgreen bg\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'default nil t)))
+                ,(add-props
+                  "red fg"
+                  `((0 . 6)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "red fg green bg"
+                  `((0 . 15)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green bg"
+                  `((0 . 8)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'default nil t))))
+     :cursor '(5 . 1))
+    (output "\e[27;49mnormal\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'default nil t)))
+                ,(add-props
+                  "red fg"
+                  `((0 . 6)
+                    :foreground ,(face-background
+                                  'default nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "red fg green bg"
+                  `((0 . 15)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green bg"
+                  `((0 . 8)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'default nil t)))
+                "normal")
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-blink ()
+  "Test SGR blink attributes (both slow and fast blink)."
+  (eat--tests-with-term '()
+    (output "\e[5mslow\n")
+    (should-term
+     :display `(,(add-props "slow" `((0 . 4) :blink slow)))
+     :cursor '(2 . 1))
+    (output "\e[6mfast\n")
+    (should-term
+     :display `(,(add-props "slow" `((0 . 4) :blink slow))
+                ,(add-props "fast" `((0 . 4) :blink fast)))
+     :cursor '(3 . 1))
+    (output "\e[25mnormal\n")
+    (should-term
+     :display `(,(add-props "slow" `((0 . 4) :blink slow))
+                ,(add-props "fast" `((0 . 4) :blink fast))
+                "normal")
+     :cursor '(4 . 1))))
+
+(ert-deftest eat-test-sgr-conceal ()
+  (eat--tests-with-term '()
+    (output "\e[8mdefault\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t))))
+     :cursor '(2 . 1))
+    (output "\e[31mdefault with fg\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "default with fg"
+                  `((0 . 15)
+                    :foreground ,(face-background
+                                  'default nil t))))
+     :cursor '(3 . 1))
+    (output "\e[41mred\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "default with fg"
+                  `((0 . 15)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t))))
+     :cursor '(4 . 1))
+    (output "\e[31;42mgreen\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "default with fg"
+                  `((0 . 15)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(5 . 1))
+    (output "\e[28mred on green\n")
+    (should-term
+     :display `(,(add-props
+                  "default"
+                  `((0 . 7)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "default with fg"
+                  `((0 . 15)
+                    :foreground ,(face-background
+                                  'default nil t)))
+                ,(add-props
+                  "red"
+                  `((0 . 3)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-1 nil t)))
+                ,(add-props
+                  "green"
+                  `((0 . 5)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-2 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t)))
+                ,(add-props
+                  "red on green"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-1 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-font ()
+  "Test SGR font attributes."
+  (eat--tests-with-term '()
+    (output "font 0\n")
+    (should-term
+     :display '("font 0")
+     :cursor '(2 . 1))
+    (should-term
+     :display `(,(add-props "font 0" `((0 . 6) :font 0)))
+     :cursor '(2 . 1))
+    (output "\e[13mfont 3\n")
+    (should-term
+     :display `("font 0"
+                ,(add-props "font 3" `((0 . 6) :font 3)))
+     :cursor '(3 . 1))
+    (output "\e[19mfont 9\n")
+    (should-term
+     :display `("font 0"
+                ,(add-props "font 3" `((0 . 6) :font 3))
+                ,(add-props "font 9" `((0 . 6) :font 9)))
+     :cursor '(4 . 1))
+    (output "\e[12mfont 2\n")
+    (should-term
+     :display `("font 0"
+                ,(add-props "font 3" `((0 . 6) :font 3))
+                ,(add-props "font 9" `((0 . 6) :font 9))
+                ,(add-props "font 2" `((0 . 6) :font 2)))
+     :cursor '(5 . 1))
+    (output "\e[10mfont 0, normal\n")
+    (should-term
+     :display `("font 0"
+                ,(add-props "font 3" `((0 . 6) :font 3))
+                ,(add-props "font 9" `((0 . 6) :font 9))
+                ,(add-props "font 2" `((0 . 6) :font 2))
+                "font 0, normal")
+     :cursor '(6 . 1))))
+
+(ert-deftest eat-test-sgr-reset ()
+  "Test SGR attributes reset sequence."
+  (eat--tests-with-term '(:width 30 :height 10)
+    (output "\e[1;3;4:3;6;7;9;15;33;105;"
+            "58;5;10mcrazy text 1\n")
+    (should-term
+     :display `(,(add-props
+                  "crazy text 1"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-13 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :intensity bold
+                    :italic t
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-10 nil t)
+                    :blink fast
+                    :crossed t
+                    :font 5)))
+     :cursor '(2 . 1))
+    (output "\e[0mnormal text 1\r\n")
+    (should-term
+     :display `(,(add-props
+                  "crazy text 1"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-13 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :intensity bold
+                    :italic t
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-10 nil t)
+                    :blink fast
+                    :crossed t
+                    :font 5))
+                "normal text 1")
+     :cursor '(3 . 1))
+    (output "\e[2;3;4:1;5;7;8;9;18;"
+            "38;2;50;90;100;48;2;100;50;9;"
+            "58;2;10;90;45mcrazy text 2\n")
+    (should-term
+     :display `(,(add-props
+                  "crazy text 1"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-13 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :intensity bold
+                    :italic t
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-10 nil t)
+                    :blink fast
+                    :crossed t
+                    :font 5))
+                "normal text 1"
+                ,(add-props
+                  "crazy text 2"
+                  '((0 . 12)
+                    :foreground "#643209"
+                    :background "#643209"
+                    :intensity faint
+                    :italic t
+                    :underline-type line
+                    :underline-color "#0a5a2d"
+                    :blink slow
+                    :crossed t
+                    :font 8)))
+     :cursor '(4 . 1))
+    (output "\e[mnormal text 2\n")
+    (should-term
+     :display `(,(add-props
+                  "crazy text 1"
+                  `((0 . 12)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-13 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :intensity bold
+                    :italic t
+                    :underline-type wave
+                    :underline-color ,(face-foreground
+                                       'eat-term-color-10 nil t)
+                    :blink fast
+                    :crossed t
+                    :font 5))
+                "normal text 1"
+                ,(add-props
+                  "crazy text 2"
+                  '((0 . 12)
+                    :foreground "#643209"
+                    :background "#643209"
+                    :intensity faint
+                    :italic t
+                    :underline-type line
+                    :underline-color "#0a5a2d"
+                    :blink slow
+                    :crossed t
+                    :font 8))
+                "normal text 2")
+     :cursor '(5 . 1))))
+
+
+;;;;; Text Manipulation Tests.
+
+(ert-deftest eat-test-insert-character ()
+  "Test insert character control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "in the universe,\nthere are\nbugs and antibugs\n"
+            "iwritebothoftheme")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "iwritebothoftheme")
+                 :cursor '(4 . 18))
+    (output "\e[2G\e[@")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "i writebothoftheme")
+                 :cursor '(4 . 2))
+    (output "\e[6C\e[1@")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "i write bothoftheme")
+                 :cursor '(4 . 8))
+    (output "\e[5C\e[@")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "i write both oftheme")
+                 :cursor '(4 . 13))
+    (output "\e[3C\e[0@")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "i write both of them")
+                 :cursor '(4 . 16))
+    ;; With background.
+    (output "\nfoobar\e[3D")
+    (should-term :display '("in the universe,"
+                            "there are"
+                            "bugs and antibugs"
+                            "i write both of them"
+                            "foobar")
+                 :cursor '(5 . 4))
+    (output "\e[40m\e[@")
+    (should-term
+     :display `("in the universe,"
+                "there are"
+                "bugs and antibugs"
+                "i write both of them"
+                ,(add-props
+                  "foo bar"
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 4))
+    (output "\e[107m\e[0@")
+    (should-term
+     :display `("in the universe,"
+                "there are"
+                "bugs and antibugs"
+                "i write both of them"
+                ,(add-props
+                  "foo  bar"
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))
+                  `((4 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 4))
+    (output "\e[48;5;133m\e[1@")
+    (should-term
+     :display `("in the universe,"
+                "there are"
+                "bugs and antibugs"
+                "i write both of them"
+                ,(add-props
+                  "foo   bar"
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-133 nil t))
+                  `((4 . 5)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))
+                  `((5 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 4))
+    (output "\e[48;2;50;255;62m\e[5@")
+    (should-term
+     :display `("in the universe,"
+                "there are"
+                "bugs and antibugs"
+                "i write both of them"
+                ,(add-props
+                  "foo        bar"
+                  '((3 . 8)
+                    :background "#32ff3e")
+                  `((8 . 9)
+                    :background ,(face-foreground
+                                  'eat-term-color-133 nil t))
+                  `((9 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))
+                  `((10 . 11)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 4))
+    (output "\e[49m\e[3@")
+    (should-term
+     :display `("in the universe,"
+                "there are"
+                "bugs and antibugs"
+                "i write both of them"
+                ,(add-props
+                  "foo           bar"
+                  '((6 . 11)
+                    :background "#32ff3e")
+                  `((11 . 12)
+                    :background ,(face-foreground
+                                  'eat-term-color-133 nil t))
+                  `((12 . 13)
+                    :background ,(face-foreground
+                                  'eat-term-color-15 nil t))
+                  `((13 . 14)
+                    :background ,(face-foreground
+                                  'eat-term-color-0 nil t))))
+     :cursor '(5 . 4))))
+
+(ert-deftest eat-test-delete-character ()
+  "Test delete character control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "sun is an star")
+    (should-term :display '("sun is an star")
+                 :cursor '(1 . 15))
+    (output "\e[6D\e[P")
+    (should-term :display '("sun is a star")
+                 :cursor '(1 . 9))
+    (output "\nmars is an exoplanet")
+    (should-term :display '("sun is a star"
+                            "mars is an exoplanet")
+                 :cursor '(2 . 20))
+    (output "\e[9D\e[3P")
+    (should-term :display '("sun is a star"
+                            "mars is an planet")
+                 :cursor '(2 . 12))
+    (output "\e[2D\e[0P")
+    (should-term :display '("sun is a star"
+                            "mars is a planet")
+                 :cursor '(2 . 10))
+    ;; With background.
+    (output "\nnill isn't false")
+    (should-term :display '("sun is a star"
+                            "mars is a planet"
+                            "nill isn't false")
+                 :cursor '(3 . 17))
+    (output "\e[3G\e[46m\e[P\e[49m")
+    (should-term
+     :display `("sun is a star"
+                "mars is a planet"
+                ,(add-props
+                  "nil isn't false     "
+                  `((19 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-6 nil t))))
+     :cursor '(3 . 3))
+    (output "\e[7G\e[48;5;14m\e[3P\e[49m")
+    (should-term
+     :display `("sun is a star"
+                "mars is a planet"
+                ,(add-props
+                  "nil is false        "
+                  `((16 . 17)
+                    :background ,(face-foreground
+                                  'eat-term-color-6 nil t))
+                  `((17 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-14 nil t))))
+     :cursor '(3 . 7))
+    (output "\nemacs is awesomes")
+    (should-term
+     :display `("sun is a star"
+                "mars is a planet"
+                ,(add-props
+                  "nil is false        "
+                  `((16 . 17)
+                    :background ,(face-foreground
+                                  'eat-term-color-6 nil t))
+                  `((17 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-14 nil t)))
+                "emacs is awesomes")
+     :cursor '(4 . 18))
+    (output "\e[D\e[48;2;226;43;93m\e[0P\e[49m")
+    (should-term
+     :display `("sun is a star"
+                "mars is a planet"
+                ,(add-props
+                  "nil is false        "
+                  `((16 . 17)
+                    :background ,(face-foreground
+                                  'eat-term-color-6 nil t))
+                  `((17 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-14 nil t)))
+                ,(add-props
+                  "emacs is awesome    "
+                  '((19 . 20)
+                    :background "#e22b5d")))
+     :cursor '(4 . 17))))
+
+(ert-deftest eat-test-erase-character ()
+  "Test erase character control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "abbcccddddee")
+    (should-term :display '("abbcccddddee")
+                 :cursor '(1 . 13))
+    (output "\e[2`\e[X")
+    (should-term :display '("a bcccddddee")
+                 :cursor '(1 . 2))
+    (output "\e[2C\e[1X")
+    (should-term :display '("a b ccddddee")
+                 :cursor '(1 . 4))
+    (output "\e[2C\e[2X")
+    (should-term :display '("a b c  dddee")
+                 :cursor '(1 . 6))
+    (output "\e[3C\e[2X")
+    (should-term :display '("a b c  d  ee")
+                 :cursor '(1 . 9))
+    (output "\e[3C\e[0X")
+    (should-term :display '("a b c  d  e")
+                 :cursor '(1 . 12))
+    ;; With background.
+    (output "\nabbcccddddee")
+    (should-term :display '("a b c  d  e"
+                            "abbcccddddee")
+                 :cursor '(2 . 13))
+    (output "\e[2`\e[42m\e[X")
+    (should-term
+     :display `("a b c  d  e"
+                ,(add-props
+                  "a bcccddddee"
+                  `((1 . 2)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))))
+     :cursor '(2 . 2))
+    (output "\e[2C\e[48;5;42m\e[1X")
+    (should-term
+     :display `("a b c  d  e"
+                ,(add-props
+                  "a b ccddddee"
+                  `((1 . 2)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-42 nil t))))
+     :cursor '(2 . 4))
+    (output "\e[2C\e[48;2;0;46;160m\e[2X")
+    (should-term
+     :display `("a b c  d  e"
+                ,(add-props
+                  "a b c  dddee"
+                  `((1 . 2)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-42 nil t))
+                  '((5 . 7)
+                    :background "#002ea0")))
+     :cursor '(2 . 6))
+    (output "\e[3C\e[103m\e[2X")
+    (should-term
+     :display `("a b c  d  e"
+                ,(add-props
+                  "a b c  d  ee"
+                  `((1 . 2)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-42 nil t))
+                  '((5 . 7)
+                    :background "#002ea0")
+                  `((8 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-11 nil t))))
+     :cursor '(2 . 9))
+    (output "\e[3C\e[48;2;162;96;198m\e[0X")
+    (should-term
+     :display `("a b c  d  e"
+                ,(add-props
+                  "a b c  d  e "
+                  `((1 . 2)
+                    :background ,(face-foreground
+                                  'eat-term-color-2 nil t))
+                  `((3 . 4)
+                    :background ,(face-foreground
+                                  'eat-term-color-42 nil t))
+                  '((5 . 7)
+                    :background "#002ea0")
+                  `((8 . 10)
+                    :background ,(face-foreground
+                                  'eat-term-color-11 nil t))
+                  '((11 . 12)
+                    :background "#a260c6")))
+     :cursor '(2 . 12))))
+
+(ert-deftest eat-test-repeat ()
+  "Test repeat control function."
+  (eat--tests-with-term '()
+    ;; Without SGR attributes.
+    (output "a\e[b")
+    (should-term :display '("aa")
+                 :cursor '(1 . 3))
+    (output "\nb\e[2b")
+    (should-term :display '("aa"
+                            "bbb")
+                 :cursor '(2 . 4))
+    (output "\nc\e[0b")
+    (should-term :display '("aa"
+                            "bbb"
+                            "cc")
+                 :cursor '(3 . 3))
+    ;; With SGR attributes.
+    (output "\n\e[34;43md\e[b")
+    (should-term
+     :display `("aa"
+                "bbb"
+                "cc"
+                ,(add-props
+                  "dd"
+                  `((0 . 2)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t))))
+     :cursor '(4 . 3))
+    (output "\n\e[;1;11me\e[5b")
+    (should-term
+     :display `("aa"
+                "bbb"
+                "cc"
+                ,(add-props
+                  "dd"
+                  `((0 . 2)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)))
+                ,(add-props
+                  "eeeeee"
+                  '((0 . 6)
+                    :intensity bold
+                    :font 1)))
+     :cursor '(5 . 7))
+    (output "\n\e[;2;5mf\e[0b")
+    (should-term
+     :display `("aa"
+                "bbb"
+                "cc"
+                ,(add-props
+                  "dd"
+                  `((0 . 2)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)))
+                ,(add-props
+                  "eeeeee"
+                  '((0 . 6)
+                    :intensity bold
+                    :font 1))
+                ,(add-props
+                  "ff"
+                  '((0 . 2)
+                    :intensity faint
+                    :blink slow)))
+     :cursor '(6 . 3))))
+
+(ert-deftest eat-test-insert-line ()
+  "Test insert line control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "early to bed and\nearly to rise,\nmakes a man\n"
+            "healthy, wealthy,\nand wise")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,"
+                            "and wise")
+                 :cursor '(5 . 9))
+    (output "\e[L")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,"
+                            ""
+                            "and wise")
+                 :cursor '(5 . 9))
+    (output "\e[2;15H\e[3L")
+    (should-term :display '("early to bed and"
+                            ""
+                            ""
+                            ""
+                            "early to rise,"
+                            "makes a man")
+                 :cursor '(2 . 15))
+    (output "\e[0L")
+    (should-term :display '("early to bed and"
+                            ""
+                            ""
+                            ""
+                            ""
+                            "early to rise,")
+                 :cursor '(2 . 15))
+    ;; With background.
+    (output "\e[2Jearly to bed and\nearly to rise,\nmakes a man\n"
+            "healthy, wealthy,\nand wise")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,"
+                            "and wise")
+                 :cursor '(5 . 9))
+    (output "\e[44m\e[L")
+    (should-term
+     :display `("early to bed and"
+                "early to rise,"
+                "makes a man"
+                "healthy, wealthy,"
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)))
+                "and wise")
+     :cursor '(5 . 9))
+    (output "\e[2;15H\e[100m\e[3L")
+    (should-term
+     :display `("early to bed and"
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                "early to rise,"
+                "makes a man")
+     :cursor '(2 . 15))
+    (output "\e[48;2;100;100;50m\e[0L")
+    (should-term
+     :display `("early to bed and"
+                ,(add-props
+                  "                    "
+                  '((0 . 20)
+                    :background "#646432"))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                "early to rise,")
+     :cursor '(2 . 15))
+    (output "\e[49m\e[1L")
+    (should-term
+     :display `("early to bed and"
+                ""
+                ,(add-props
+                  "                    "
+                  '((0 . 20)
+                    :background "#646432"))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(2 . 15))))
+
+(ert-deftest eat-test-delete-line ()
+  "Test insert line control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "early to bed and\nearly to rise,\nmakes a man\n"
+            "healthy, wealthy,\nand wise")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,"
+                            "and wise")
+                 :cursor '(5 . 9))
+    (output "\e[M")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,")
+                 :cursor '(5 . 9))
+    (output "\e[2;15H\e[3M")
+    (should-term :display '("early to bed and")
+                 :cursor '(2 . 15))
+    (output "\e[;5H\e[0M")
+    (should-term :cursor '(1 . 5))
+    ;; With background.
+    (output "\e[Hearly to bed and\nearly to rise,\nmakes a man\n"
+            "healthy, wealthy,\nand wise")
+    (should-term :display '("early to bed and"
+                            "early to rise,"
+                            "makes a man"
+                            "healthy, wealthy,"
+                            "and wise")
+                 :cursor '(5 . 9))
+    (output "\e[44m\e[M")
+    (should-term
+     :display `("early to bed and"
+                "early to rise,"
+                "makes a man"
+                "healthy, wealthy,"
+                ""
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t))))
+     :cursor '(5 . 9))
+    (output "\e[2;15H\e[100m\e[3M")
+    (should-term
+     :display `("early to bed and"
+                ""
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(2 . 15))
+    (output "\e[H\e[48;2;100;100;50m\e[0M")
+    (should-term
+     :display `(""
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  '((0 . 20)
+                    :background "#646432")))
+     :cursor '(1 . 1))
+    (output "\e[49m\e[1M")
+    (should-term
+     :display `(,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "                    "
+                  '((0 . 20)
+                    :background "#646432")))
+     :cursor '(1 . 1))))
+
+(ert-deftest eat-test-erase-in-line ()
+  "Test erase in line control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "foo bar baz\e[6G")
+    (should-term :display '("foo bar baz")
+                 :cursor '(1 . 6))
+    (output "\e[K")
+    (should-term :display '("foo b")
+                 :cursor '(1 . 6))
+    (output "\nbar baz foo\e[6G")
+    (should-term :display '("foo b"
+                            "bar baz foo")
+                 :cursor '(2 . 6))
+    (output "\e[1K")
+    (should-term :display '("foo b"
+                            "      z foo")
+                 :cursor '(2 . 6))
+    (output "\nbaz foo bar\e[6G")
+    (should-term :display '("foo b"
+                            "      z foo"
+                            "baz foo bar")
+                 :cursor '(3 . 6))
+    (output "\e[0K")
+    (should-term :display '("foo b"
+                            "      z foo"
+                            "baz f")
+                 :cursor '(3 . 6))
+    (output "\nfoo bar baz\e[6G")
+    (should-term :display '("foo b"
+                            "      z foo"
+                            "baz f"
+                            "foo bar baz")
+                 :cursor '(4 . 6))
+    (output "\e[2K")
+    (should-term :display '("foo b"
+                            "      z foo"
+                            "baz f")
+                 :cursor '(4 . 6))
+    ;; With background.
+    (output "\nfoo bar baz\e[6G")
+    (should-term :display '("foo b"
+                            "      z foo"
+                            "baz f"
+                            ""
+                            "foo bar baz")
+                 :cursor '(5 . 6))
+    (output "\e[47m\e[K\e[m")
+    (should-term
+     :display `("foo b"
+                "      z foo"
+                "baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t))))
+     :cursor '(5 . 6))
+    (output "\nbar baz foo\e[6G")
+    (should-term
+     :display `("foo b"
+                "      z foo"
+                "baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                "bar baz foo")
+     :cursor '(6 . 6))
+    (output "\e[100m\e[1K\e[m")
+    (should-term
+     :display `("foo b"
+                "      z foo"
+                "baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t))))
+     :cursor '(6 . 6))
+    (output "\nbaz foo bar\e[6G")
+    (should-term
+     :scrollback '("foo b")
+     :display `("      z foo"
+                "baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                "baz foo bar")
+     :cursor '(6 . 6))
+    (output "\e[48;5;55m\e[0K\e[m")
+    (should-term
+     :scrollback '("foo b")
+     :display `("      z foo"
+                "baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "baz f                 "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-55 nil t))))
+     :cursor '(6 . 6))
+    (output "\nfoo bar baz\e[6G")
+    (should-term
+     :scrollback '("foo b"
+                   "      z foo")
+     :display `("baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "baz f                 "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-55 nil t)))
+                "foo bar baz")
+     :cursor '(6 . 6))
+    (output "\e[48;2;255;255;255m\e[2K")
+    (should-term
+     :scrollback '("foo b"
+                   "      z foo")
+     :display `("baz f"
+                ""
+                ,(add-props
+                  "foo b               "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-7 nil t)))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :background ,(face-foreground
+                                  'eat-term-color-8 nil t)))
+                ,(add-props
+                  "baz f                 "
+                  `((5 . 20)
+                    :background ,(face-foreground
+                                  'eat-term-color-55 nil t)))
+                ,(add-props
+                  "                      "
+                  '((0 . 20)
+                    :background "#ffffff")))
+     :cursor '(6 . 6))))
+
+(ert-deftest eat-test-erase-in-display ()
+  "Test erase in display control function."
+  (eat--tests-with-term '()
+    ;; Without background.
+    (output "foo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[J")
+    (should-term :display '("foo bar baz"
+                            "bar b")
+                 :cursor '(2 . 6))
+    (output "\e[Hfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[1J")
+    (should-term :display '(""
+                            "      z foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[Hfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[0J")
+    (should-term :display '("foo bar baz"
+                            "bar b")
+                 :cursor '(2 . 6))
+    (output "\e[Hfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[2J")
+    (should-term :cursor '(1 . 1))
+    (output "foo bar baz\nbar baz foo\nbaz foo bar\n"
+            "foo bar baz\nbar baz foo\nbaz foo bar\n")
+    (should-term :scrollback '("foo bar baz")
+                 :display '("bar baz foo"
+                            "baz foo bar"
+                            "foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(6 . 1))
+    (output "\e[3J")
+    (should-term :cursor '(1 . 1))
+    ;; With background.
+    (output "foo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[11;33;44m\e[J\e[m")
+    (should-term
+     :display `("foo bar baz"
+                ,(add-props
+                  "bar b               "
+                  `((5 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :font 1)))
+     :cursor '(2 . 6))
+    (output "\e[2Jfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[1;97;103m\e[1J\e[m")
+    (should-term
+     :display `(,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-11 nil t)
+                    :intensity bold))
+                ,(add-props
+                  "      z foo"
+                  `((0 . 6)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-15 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-11 nil t)
+                    :intensity bold))
+                "baz foo bar")
+     :cursor '(2 . 6))
+    (output "\e[2Jfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[11;34;43m\e[0J\e[m")
+    (should-term
+     :display `("foo bar baz"
+                ,(add-props
+                  "bar b               "
+                  `((5 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :font 1))
+                ,(add-props
+                  "                    "
+                  `((0 . 20)
+                    :foreground ,(face-foreground
+                                  'eat-term-color-4 nil t)
+                    :background ,(face-foreground
+                                  'eat-term-color-3 nil t)
+                    :font 1)))
+     :cursor '(2 . 6))
+    (output "\e[2Jfoo bar baz\nbar baz foo\nbaz foo bar\e[2;6H")
+    (should-term :display '("foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(2 . 6))
+    (output "\e[48;2;50;200;100m\e[2J\e[m")
+    (should-term
+     :display `(,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#32c864")))
+     :cursor '(1 . 1))
+    (output "\e[2Jfoo bar baz\nbar baz foo\nbaz foo bar\n"
+            "foo bar baz\nbar baz foo\nbaz foo bar\n")
+    (should-term :scrollback '("foo bar baz")
+                 :display '("bar baz foo"
+                            "baz foo bar"
+                            "foo bar baz"
+                            "bar baz foo"
+                            "baz foo bar")
+                 :cursor '(6 . 1))
+    (output "\e[48;2;20;5;200m\e[3J\e[m")
+    (should-term
+     :display `(,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8"))
+                ,(add-props
+                  "                    "
+                  '((0 . 20) :background "#1405c8")))
+     :cursor '(1 . 1))))
+
+
+;;;;; Resizing Tests.
+
+(ert-deftest eat-test-resize-when-at-beginning-of-first-line ()
+  "Test resize when on the beginning of the first line of display."
+  (eat--tests-with-term '()
+    (output "1\n2\n3\n4\n5\n6\e[H")
+    (should-term :display '("1"
+                            "2"
+                            "3"
+                            "4"
+                            "5"
+                            "6")
+                 :cursor '(1 . 1))
+    (eat-term-resize (terminal) 20 5)
+    (should-term :scrollback '("1")
+                 :display '("2"
+                            "3"
+                            "4"
+                            "5"
+                            "6")
+                 :cursor '(1 . 1))
+    (output "7\n")
+    (should-term :scrollback '("1")
+                 :display '("7"
+                            "3"
+                            "4"
+                            "5"
+                            "6")
+                 :cursor '(2 . 1))))
+
+(ert-deftest eat-test-resize-when-at-beginning-of-last-line ()
+  "Test resize when on the beginning of the last line of display."
+  (eat--tests-with-term '()
+    (output "1\n2\n3\n4\n5\n")
+    (should-term :display '("1"
+                            "2"
+                            "3"
+                            "4"
+                            "5")
+                 :cursor '(6 . 1))
+    (eat-term-resize (terminal) 20 5)
+    (should-term :scrollback '("1")
+                 :display '("2"
+                            "3"
+                            "4"
+                            "5")
+                 :cursor '(5 . 1))
+    (output "6\n")
+    (should-term :scrollback '("1"
+                               "2")
+                 :display '("3"
+                            "4"
+                            "5"
+                            "6")
+                 :cursor '(5 . 1))))
+
+(ert-deftest eat-test-resize-alternative-display ()
+  "Test resize when the beginning of the first line on display."
+  (eat--tests-with-term '()
+    (output "\e[?1049htoo looooooooooooong\nl\no\no\nn\ng")
+    (should-term :display '("too looooooooooooong"
+                            "l"
+                            "o"
+                            "o"
+                            "n"
+                            "g")
+                 :cursor '(6 . 2))
+    (eat-term-resize (terminal) 18 4)
+    (should-term :display '("too looooooooooooo"
+                            "l"
+                            "o"
+                            "o")
+                 :cursor '(4 . 2))))
+
+
+;;;;; Miscellaneous Tests.
+
+(ert-deftest eat-test-bell ()
+  "Test bell control function."
+  (eat--tests-with-term '()
+    (let ((bell-rang nil))
+      (setf (eat-term-ring-bell-function (terminal))
+            (lambda (term)
+              (should (eq term (terminal)))
+              (setq bell-rang t)))
+      (output "\a")
+      (should bell-rang))))
+
+(ert-deftest eat-test-character-sets ()
+  "Test character sets."
+  (eat--tests-with-term '()
+    (output "some text")
+    (should-term :display '("some text")
+                 :cursor '(1 . 10))
+    (output "\n\e(0some text")
+    (should-term :display '("some text"
+                            "⎽⎺└␊ ├␊│├")
+                 :cursor '(2 . 10))
+    (output "\n\e(Bsome text")
+    (should-term :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text")
+                 :cursor '(3 . 10))
+    (output "\n\C-nsome text")
+    (should-term :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text")
+                 :cursor '(4 . 10))
+    (output "\n\e)0some text")
+    (should-term :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├")
+                 :cursor '(5 . 10))
+    (output "\n\e)Bsome text")
+    (should-term :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\ensome text")
+    (should-term :scrollback '("some text")
+                 :display '("⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\e*0some text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├")
+                 :display '("some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├")
+                 :cursor '(6 . 10))
+    (output "\n\e*Bsome text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text")
+                 :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\eosome text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text")
+                 :display '("⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\e+0some text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├")
+                 :display '("some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├")
+                 :cursor '(6 . 10))
+    (output "\n\e+Bsome text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text")
+                 :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\C-osome text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text")
+                 :display '("⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\e(0some text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├")
+                 :display '("some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├")
+                 :cursor '(6 . 10))
+    (output "\n\e(Bsome text")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text")
+                 :display '("some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text")
+                 :cursor '(6 . 10))
+    (output "\n\e(0+,-.0`abcdefghijklmnopqrstuvwxyz{|}~")
+    (should-term :scrollback '("some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├"
+                               "some text"
+                               "some text"
+                               "⎽⎺└␊ ├␊│├")
+                 :display '("some text"
+                            "some text"
+                            "⎽⎺└␊ ├␊│├"
+                            "some text"
+                            "→←↑↓█�▒␉␌␍␊°±░#┘┐┌└┼"
+                            "⎺⎻─⎼⎽├┤┴┬│≤≥π≠£•")
+                 :cursor '(6 . 17))))
+
+(ert-deftest eat-test-save-and-restore-cursor ()
+  "Test saving and restoring cursor position.
+
+Write plain text and newline to move cursor."
+  (eat--tests-with-term '()
+    (output "foo")
+    (should-term :display '("foo")
+                 :cursor '(1 . 4))
+    (output "\e7")
+    (should-term :display '("foo")
+                 :cursor '(1 . 4))
+    (output "bar\nfrob")
+    (should-term :display '("foobar"
+                            "frob")
+                 :cursor '(2 . 5))
+    (output "\e8")
+    (should-term :display '("foobar"
+                            "frob")
+                 :cursor '(1 . 4))))
+
+
+;;;;; Input Event Tests.
+
+(ert-deftest eat-test-input-character ()
+  "Test character input events.
+
+This includes all events to which `self-insert-command' is bound to by
+default."
+  (eat--tests-with-term '()
+    (dolist (c '(?a ?E ?b ?D ?অ ?আ ?ক ?খ ?ম ?া ?π ?θ ?μ ?Δ))
+      (input-event c)
+      (should (string= (input) (string c))))))
+
+(ert-deftest eat-test-input-character-with-modifier ()
+  "Test character input events with modifiers (`control' and `meta').
+
+This includes all events to which `self-insert-command' is bound to by
+default."
+  (eat--tests-with-term '()
+    (dolist (p '((?\C-\  . "\C-@")
+                 (?\C-a . "\C-a")
+                 (?\C-E . "\C-e")
+                 (?\C-b . "\C-b")
+                 (?\C-D . "\C-d")
+                 (?\M-x . "\ex")
+                 (?\M-O . "\e")
+                 (?\M-\[ . "\e")
+                 (?\M-C . "\eC")
+                 (?\C-\M-U . "\e\C-u")
+                 (?\M-ম . "\eম")
+                 (?\M-া . "\eা")
+                 (?\M-π . "\eπ")
+                 (?\M-θ . "\eθ")))
+      (input-event (car p))
+      (should (string= (input) (cdr p))))))
+
+(ert-deftest eat-test-input-special-keys ()
+  "Test special key input events like arrow keys, backspace, etc."
+  (eat--tests-with-term '()
+    (cl-labels ((check (alist)
+                  (dolist (p alist)
+                    (input-event (car p))
+                    (should (string= (input) (cdr p))))))
+      (check '((backspace . "\C-?")
+               (C-backspace . "\C-h")
+               (left . "\e[D")
+               (C-right . "\e[1;5C")
+               (M-up . "\e[1;3A")
+               (S-down . "\e[1;2B")
+               (C-M-insert . "\e[2;7~")
+               (C-S-delete . "\e[3;6~")
+               (M-S-deletechar . "\e[3;4~")
+               (C-M-S-home . "\e[1;8H")
+               (C-S-end . "\e[1;6F")
+               (M-S-prior . "\e[5;4~")
+               (next . "\e[6~")))
+      (output "\e[?1h")
+      (check '((left . "\eOD")
+               (up . "\eOA")
+               (C-right . "\e[1;5C")
+               (M-up . "\e[1;3A")
+               (S-down . "\e[1;2B")))
+      (output "\e[?1l")
+      (check '((up . "\e[A"))))))
+
+(ert-deftest eat-test-input-focus-events ()
+  "Test focus events."
+  (eat--tests-with-term '()
+    (let ((focus-event-enabled nil))
+      (setf (eat-term-grab-focus-events-function (terminal))
+            (lambda (term value)
+              (should (eq term (terminal)))
+              (setq focus-event-enabled value)))
+      (cl-labels ((check (alist)
+                    (dolist (p alist)
+                      (input-event (car p))
+                      (should (string= (input) (cdr p))))))
+        (check '(((eat-focus-in) . "")
+                 ((eat-focus-out) . "")))
+        (output "\e[?1004h")
+        ;; The mode is MUST BE t, not non-nil.
+        (should (eq focus-event-enabled t))
+        (check '(((eat-focus-in) . "\e[I")
+                 ((eat-focus-out) . "\e[O")))
+        (output "\e[?1004l")
+        (should (eq focus-event-enabled nil))
+        (check '(((eat-focus-in) . "")
+                 ((eat-focus-out) . "")))))))
+
+(ert-deftest eat-test-input-mouse-events ()
+  "Test focus events."
+  (eat--tests-with-term '(:width 200 :height 200)
+    (cl-letf* ((mouse-mode nil)
+               ((eat-term-grab-mouse-function (terminal))
+                (lambda (term mouse)
+                  (should (eq term (terminal)))
+                  (setq mouse-mode mouse)))
+               ((symbol-function #'posn-col-row)
+                (lambda (posn &optional _use-window)
+                  (nth 6 posn))))
+      (cl-labels ((check (alist)
+                    (dolist (p alist)
+                      (input-event (car p) (cadr p))
+                      (should (string= (input) (caddr p)))))
+                  (make-posn (&key (window (selected-window))
+                                   pos-or-area (timestamp 0)
+                                   (object (point-min)) text-pos
+                                   (col 0) (row 0) (x col) (y row)
+                                   image (dx x) (dy y) (width 1)
+                                   (height 1))
+                    `( ,window ,pos-or-area (,x . ,y) ,timestamp
+                       ,object ,text-pos (,col . ,row) ,image
+                       (,dx . ,dy) (,width . ,height))))
+
+        ;; Default mouse event encoding.
+        ;; Mouse mode disabled.
+        (check
+         `(((mouse-1 ,(make-posn)) nil "")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "")
+           ((mouse-3 ,(make-posn :col 8 :row 3))
+            ,(make-posn :col 1 :row 1) "")
+           ((mouse-4 ,(make-posn :col 13 :row 4))
+            ,(make-posn :col 5 :row 1) "")
+           ((mouse-movement ,(make-posn :col 90 :row 40))
+            ,(make-posn :col 82 :row 33) "")))
+
+        ;; X10 mouse mode.
+        (output "\e[?9h")
+        (should (eq mouse-mode :click))
+        (check
+         `(((mouse-1 ,(make-posn)) nil "\e[M !!")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "\e[M!!!")
+           ((mouse-3 ,(make-posn :col 10 :row 5))
+            ,(make-posn :col 6 :row 3) "\e[M\"%#")
+           ;; Position out of range of default mouse event encoding.
+           ((mouse-1 ,(make-posn :col 95 :row 5)) nil "")
+           ;; Position not inside terminal.
+           ((mouse-2 ,(make-posn :col 94 :row 5))
+            ,(make-posn :col 96 :row 5) "")
+           ((mouse-2 ,(make-posn :col 95 :row 4))
+            ,(make-posn :col 96 :row 8) "")
+           ((mouse-4 ,(make-posn :col 24 :row 9))
+            ,(make-posn :col 8 :row 4) "")
+           ((mouse-movement ,(make-posn :col 30 :row 45))
+            ,(make-posn :col 28 :row 42) "")))
+
+        ;; Normal mouse mode.
+        (output "\e[?1000h")
+        (should (eq mouse-mode :modifier-click))
+        (check
+         `(((down-mouse-1 ,(make-posn)) nil "\e[M !!")
+           ((mouse-1 ,(make-posn)) nil "\e[M#!!")
+           ((down-mouse-2 ,(make-posn)) ,(make-posn) "\e[M!!!")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "\e[M#!!")
+           ((down-mouse-3 ,(make-posn :col 10 :row 5))
+            ,(make-posn) "\e[M\"+&")
+           ;; Note that, although the mouse position has changed, it's
+           ;; still unmoved relative to the reference position, so the
+           ;; mouse position inputted should be same.
+           ((drag-mouse-3 ,(make-posn :col 10 :row 5)
+                          ,(make-posn :col 20 :row 50))
+            ,(make-posn :col 10 :row 45) "\e[M#+&")
+           ((mouse-4 ,(make-posn :col 33 :row 10))
+            ,(make-posn :col 30 :row 5) "\e[M\`$&")
+           ((C-mouse-5 ,(make-posn :col 4250 :row 3145))
+            ,(make-posn :col 4242 :row 3141) "\e[Mq)%")
+           ((M-mouse-6 ,(make-posn :col 425 :row 314))
+            ,(make-posn :col 424 :row 314) "\e[Mj\"!")
+           ((S-mouse-7 ,(make-posn :col 85 :row 20))
+            ,(make-posn :col 32 :row 16) "\e[MgV%")
+           ((C-M-down-mouse-1 ,(make-posn :col 58 :row 32))
+            ,(make-posn :col 23 :row 31) "\e[M8D\"")
+           ((C-M-mouse-1 ,(make-posn :col 58 :row 32))
+            ,(make-posn :col 23 :row 31) "\e[M;D\"")
+           ((C-S-down-mouse-2 ,(make-posn :col 40 :row 39))
+            ,(make-posn :col 33 :row 13) "\e[M5(;")
+           ;; Modifier changed!
+           ((M-S-mouse-2 ,(make-posn :col 40 :row 39))
+            ,(make-posn :col 33 :row 13) "\e[M/(;")
+           ((C-M-S-down-mouse-3 ,(make-posn :col 48 :row 29))
+            ,(make-posn :col 39 :row 23) "\e[M>*'")
+           ;; Everything changed!
+           ((mouse-3 ,(make-posn :col 92 :row 83))
+            ,(make-posn :col 10 :row 8) "\e[M#sl")
+           ;; Button out of range of default mouse event encoding.
+           ((mouse-8 ,(make-posn :col 1 :row 1))
+            ,(make-posn :col 1 :row 1) "")
+           ((mouse-movement ,(make-posn :col 49 :row 85))
+            ,(make-posn :col 45 :row 82) "")))
+
+        ;; Button event mouse mode.
+        (output "\e[?1002h")
+        (should (eq mouse-mode :drag))
+        (check
+         `(((mouse-movement ,(make-posn :col 84 :row 10))
+            ,(make-posn :col 48 :row 8) "")
+           ((down-mouse-1 ,(make-posn :col 44 :row 88))
+            ,(make-posn :col 44 :row 88) "\e[M !!")
+           ((mouse-movement ,(make-posn :col 48 :row 1))
+            ,(make-posn :col 19 :row 0) "\e[M@>\"")
+           ((down-mouse-2 ,(make-posn :col 29 :row 21))
+            ,(make-posn :col 18 :row 8) "\e[M!,.")
+           ((mouse-movement ,(make-posn :col 93 :row 54))
+            ,(make-posn :col 29 :row 38) "\e[M@a1")
+           ((down-mouse-3 ,(make-posn :col 92 :row 63))
+            ,(make-posn :col 32 :row 38) "\e[M\"]:")
+           ((mouse-movement ,(make-posn :col 8 :row 92))
+            ,(make-posn :col 3 :row 34) "\e[M@&[")
+           ((mouse-1 ,(make-posn :col 93 :row 21))
+            ,(make-posn :col 0 :row 0) "\e[M#~6")
+           ((mouse-movement ,(make-posn :col 29 :row 74))
+            ,(make-posn :col 7 :row 64) "\e[MA7+")
+           ((mouse-2 ,(make-posn :col 28 :row 92))
+            ,(make-posn :col 23 :row 29) "\e[M#&`")
+           ((mouse-movement ,(make-posn :col 75 :row 36))
+            ,(make-posn :col 75 :row 19) "\e[MB!2")
+           ((mouse-3 ,(make-posn :col 36 :row 76))
+            ,(make-posn :col 17 :row 67) "\e[M#4*")
+           ((mouse-movement ,(make-posn :col 94 :row 58))
+            ,(make-posn :col 54 :row 28) "")))
+
+        ;; All event mouse mode.
+        (output "\e[?1003h")
+        (should (eq mouse-mode :all))
+        (check
+         `(((mouse-movement ,(make-posn :col 28 :row 38))
+            ,(make-posn :col 4 :row 2) "\e[MC9E")
+           ((mouse-movement ,(make-posn :col 49 :row 85))
+            ,(make-posn :col 45 :row 82) "\e[MC%$")
+           ((mouse-movement ,(make-posn :col 84 :row 10))
+            ,(make-posn :col 48 :row 8) "\e[MCE#")
+           ((down-mouse-1 ,(make-posn :col 44 :row 88))
+            ,(make-posn :col 44 :row 88) "\e[M !!")
+           ((mouse-movement ,(make-posn :col 48 :row 1))
+            ,(make-posn :col 19 :row 0) "\e[M@>\"")
+           ((down-mouse-2 ,(make-posn :col 29 :row 21))
+            ,(make-posn :col 18 :row 8) "\e[M!,.")
+           ((mouse-movement ,(make-posn :col 93 :row 54))
+            ,(make-posn :col 29 :row 38) "\e[M@a1")
+           ((down-mouse-3 ,(make-posn :col 92 :row 63))
+            ,(make-posn :col 32 :row 38) "\e[M\"]:")
+           ((mouse-movement ,(make-posn :col 8 :row 92))
+            ,(make-posn :col 3 :row 34) "\e[M@&[")
+           ((mouse-1 ,(make-posn :col 93 :row 21))
+            ,(make-posn :col 0 :row 0) "\e[M#~6")
+           ((mouse-movement ,(make-posn :col 29 :row 74))
+            ,(make-posn :col 7 :row 64) "\e[MA7+")
+           ((mouse-2 ,(make-posn :col 28 :row 92))
+            ,(make-posn :col 23 :row 29) "\e[M#&`")
+           ((mouse-movement ,(make-posn :col 75 :row 36))
+            ,(make-posn :col 75 :row 19) "\e[MB!2")
+           ((mouse-3 ,(make-posn :col 36 :row 76))
+            ,(make-posn :col 17 :row 67) "\e[M#4*")
+           ((mouse-movement ,(make-posn :col 94 :row 58))
+            ,(make-posn :col 54 :row 28) "\e[MCI?")
+           ((mouse-movement ,(make-posn :col 97 :row 79))
+            ,(make-posn :col 46 :row 69) "\e[MCT+")
+           ((mouse-movement ,(make-posn :col 34 :row 76))
+            ,(make-posn :col 28 :row 29) "\e[MC'P")))
+
+        ;; Mouse mode disabled.
+        (output "\e[?1003l")
+        (should (eq mouse-mode nil))
+        (check
+         `(((mouse-1 ,(make-posn)) nil "")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "")
+           ((mouse-3 ,(make-posn :col 8 :row 3))
+            ,(make-posn :col 1 :row 1) "")
+           ((mouse-4 ,(make-posn :col 13 :row 4))
+            ,(make-posn :col 5 :row 1) "")
+           ((mouse-movement ,(make-posn :col 90 :row 40))
+            ,(make-posn :col 82 :row 33) "")))
+
+        ;; SGR mouse event encoding.
+        (output "\e[?1006h")
+
+        ;; Mouse mode disabled.
+        (check
+         `(((mouse-1 ,(make-posn)) nil "")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "")
+           ((mouse-3 ,(make-posn :col 8 :row 3))
+            ,(make-posn :col 1 :row 1) "")
+           ((mouse-4 ,(make-posn :col 13 :row 4))
+            ,(make-posn :col 5 :row 1) "")
+           ((mouse-movement ,(make-posn :col 90 :row 40))
+            ,(make-posn :col 82 :row 33) "")))
+
+        ;; X10 mouse mode.
+        (output "\e[?9h")
+        (should (eq mouse-mode :click))
+        (check
+         `(((mouse-1 ,(make-posn)) nil "\e[<0;1;1M")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "\e[<1;1;1M")
+           ((mouse-3 ,(make-posn :col 10 :row 5))
+            ,(make-posn :col 6 :row 3) "\e[<2;5;3M")
+           ((mouse-1 ,(make-posn :col 95 :row 5)) nil "\e[<0;96;6M")
+           ;; Position not inside terminal.
+           ((mouse-2 ,(make-posn :col 94 :row 5))
+            ,(make-posn :col 96 :row 5) "")
+           ((mouse-2 ,(make-posn :col 95 :row 4))
+            ,(make-posn :col 96 :row 8) "")
+           ((mouse-4 ,(make-posn :col 24 :row 9))
+            ,(make-posn :col 8 :row 4) "")
+           ((mouse-movement ,(make-posn :col 30 :row 45))
+            ,(make-posn :col 28 :row 42) "")))
+
+        ;; Normal mouse mode.
+        (output "\e[?1000h")
+        (should (eq mouse-mode :modifier-click))
+        (check
+         `(((down-mouse-1 ,(make-posn)) nil "\e[<0;1;1M")
+           ((mouse-1 ,(make-posn)) nil "\e[<0;1;1m")
+           ((down-mouse-2 ,(make-posn)) ,(make-posn) "\e[<1;1;1M")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "\e[<1;1;1m")
+           ((down-mouse-3 ,(make-posn :col 10 :row 5))
+            ,(make-posn) "\e[<2;11;6M")
+           ;; Note that, although the mouse position has changed, it's
+           ;; still unmoved relative to the reference position, so the
+           ;; mouse position inputted should be same.
+           ((drag-mouse-3 ,(make-posn :col 10 :row 5)
+                          ,(make-posn :col 20 :row 50))
+            ,(make-posn :col 10 :row 45) "\e[<2;11;6m")
+           ((mouse-4 ,(make-posn :col 33 :row 10))
+            ,(make-posn :col 30 :row 5) "\e[<64;4;6M")
+           ((C-mouse-5 ,(make-posn :col 4250 :row 3145))
+            ,(make-posn :col 4242 :row 3141) "\e[<81;9;5M")
+           ((M-mouse-6 ,(make-posn :col 425 :row 314))
+            ,(make-posn :col 424 :row 314) "\e[<74;2;1M")
+           ((S-mouse-7 ,(make-posn :col 85 :row 20))
+            ,(make-posn :col 32 :row 16) "\e[<71;54;5M")
+           ((mouse-8 ,(make-posn :col 91 :row 92))
+            ,(make-posn :col 75 :row 18) "\e[<128;17;75M")
+           ((mouse-9 ,(make-posn :col 71 :row 81))
+            ,(make-posn :col 37 :row 72) "\e[<129;35;10M")
+           ((mouse-10 ,(make-posn :col 38 :row 92))
+            ,(make-posn :col 29 :row 90) "\e[<130;10;3M")
+           ((mouse-11 ,(make-posn :col 29 :row 14))
+            ,(make-posn :col 28 :row 8) "\e[<131;2;7M")
+           ((C-M-down-mouse-1 ,(make-posn :col 58 :row 32))
+            ,(make-posn :col 23 :row 31) "\e[<24;36;2M")
+           ((C-M-mouse-1 ,(make-posn :col 58 :row 32))
+            ,(make-posn :col 23 :row 31) "\e[<24;36;2m")
+           ((C-S-down-mouse-2 ,(make-posn :col 40 :row 39))
+            ,(make-posn :col 33 :row 13) "\e[<21;8;27M")
+           ;; Modifier changed!
+           ((M-S-mouse-2 ,(make-posn :col 40 :row 39))
+            ,(make-posn :col 33 :row 13) "\e[<13;8;27m")
+           ((C-M-S-down-mouse-3 ,(make-posn :col 48 :row 29))
+            ,(make-posn :col 39 :row 23) "\e[<30;10;7M")
+           ;; Everything changed!
+           ((mouse-3 ,(make-posn :col 92 :row 83))
+            ,(make-posn :col 10 :row 8) "\e[<2;83;76m")
+           ((mouse-movement ,(make-posn :col 49 :row 85))
+            ,(make-posn :col 45 :row 82) "")))
+
+        ;; Button event mouse mode.
+        (output "\e[?1002h")
+        (should (eq mouse-mode :drag))
+        (check
+         `(((mouse-movement ,(make-posn :col 84 :row 10))
+            ,(make-posn :col 48 :row 8) "")
+           ((down-mouse-1 ,(make-posn :col 44 :row 88))
+            ,(make-posn :col 44 :row 88) "\e[<0;1;1M")
+           ((mouse-movement ,(make-posn :col 48 :row 1))
+            ,(make-posn :col 19 :row 0) "\e[<32;30;2M")
+           ((down-mouse-2 ,(make-posn :col 29 :row 21))
+            ,(make-posn :col 18 :row 8) "\e[<1;12;14M")
+           ((mouse-movement ,(make-posn :col 93 :row 54))
+            ,(make-posn :col 29 :row 38) "\e[<32;65;17M")
+           ((down-mouse-3 ,(make-posn :col 92 :row 63))
+            ,(make-posn :col 32 :row 38) "\e[<2;61;26M")
+           ((mouse-movement ,(make-posn :col 8 :row 92))
+            ,(make-posn :col 3 :row 34) "\e[<32;6;59M")
+           ((mouse-1 ,(make-posn :col 93 :row 21))
+            ,(make-posn :col 0 :row 0) "\e[<0;94;22m")
+           ((mouse-movement ,(make-posn :col 29 :row 74))
+            ,(make-posn :col 7 :row 64) "\e[<33;23;11M")
+           ((mouse-2 ,(make-posn :col 28 :row 92))
+            ,(make-posn :col 23 :row 29) "\e[<1;6;64m")
+           ((mouse-movement ,(make-posn :col 75 :row 36))
+            ,(make-posn :col 75 :row 19) "\e[<34;1;18M")
+           ((mouse-3 ,(make-posn :col 36 :row 76))
+            ,(make-posn :col 17 :row 67) "\e[<2;20;10m")
+           ((mouse-movement ,(make-posn :col 94 :row 58))
+            ,(make-posn :col 54 :row 28) "")))
+
+        ;; All event mouse mode.
+        (output "\e[?1003h")
+        (should (eq mouse-mode :all))
+        (check
+         `(((mouse-movement ,(make-posn :col 28 :row 38))
+            ,(make-posn :col 4 :row 2) "\e[<35;25;37M")
+           ((mouse-movement ,(make-posn :col 49 :row 85))
+            ,(make-posn :col 45 :row 82) "\e[<35;5;4M")
+           ((mouse-movement ,(make-posn :col 84 :row 10))
+            ,(make-posn :col 48 :row 8) "\e[<35;37;3M")
+           ((down-mouse-1 ,(make-posn :col 44 :row 88))
+            ,(make-posn :col 44 :row 88) "\e[<0;1;1M")
+           ((mouse-movement ,(make-posn :col 48 :row 1))
+            ,(make-posn :col 19 :row 0) "\e[<32;30;2M")
+           ((down-mouse-2 ,(make-posn :col 29 :row 21))
+            ,(make-posn :col 18 :row 8) "\e[<1;12;14M")
+           ((mouse-movement ,(make-posn :col 93 :row 54))
+            ,(make-posn :col 29 :row 38) "\e[<32;65;17M")
+           ((down-mouse-3 ,(make-posn :col 92 :row 63))
+            ,(make-posn :col 32 :row 38) "\e[<2;61;26M")
+           ((mouse-movement ,(make-posn :col 8 :row 92))
+            ,(make-posn :col 3 :row 34) "\e[<32;6;59M")
+           ((mouse-1 ,(make-posn :col 93 :row 21))
+            ,(make-posn :col 0 :row 0) "\e[<0;94;22m")
+           ((mouse-movement ,(make-posn :col 29 :row 74))
+            ,(make-posn :col 7 :row 64) "\e[<33;23;11M")
+           ((mouse-2 ,(make-posn :col 28 :row 92))
+            ,(make-posn :col 23 :row 29) "\e[<1;6;64m")
+           ((mouse-movement ,(make-posn :col 75 :row 36))
+            ,(make-posn :col 75 :row 19) "\e[<34;1;18M")
+           ((mouse-3 ,(make-posn :col 36 :row 76))
+            ,(make-posn :col 17 :row 67) "\e[<2;20;10m")
+           ((mouse-movement ,(make-posn :col 94 :row 58))
+            ,(make-posn :col 54 :row 28) "\e[<35;41;31M")
+           ((mouse-movement ,(make-posn :col 97 :row 79))
+            ,(make-posn :col 46 :row 69) "\e[<35;52;11M")
+           ((mouse-movement ,(make-posn :col 34 :row 76))
+            ,(make-posn :col 28 :row 29) "\e[<35;7;48M")))
+
+        ;; Default mouse encoding.
+        (output "\e[?1006l")
+        (check
+         `(((mouse-movement ,(make-posn :col 28 :row 38))
+            ,(make-posn :col 4 :row 2) "\e[MC9E")
+           ((mouse-movement ,(make-posn :col 49 :row 85))
+            ,(make-posn :col 45 :row 82) "\e[MC%$")
+           ((mouse-movement ,(make-posn :col 84 :row 10))
+            ,(make-posn :col 48 :row 8) "\e[MCE#")
+           ((down-mouse-1 ,(make-posn :col 44 :row 88))
+            ,(make-posn :col 44 :row 88) "\e[M !!")
+           ((mouse-movement ,(make-posn :col 48 :row 1))
+            ,(make-posn :col 19 :row 0) "\e[M@>\"")
+           ((down-mouse-2 ,(make-posn :col 29 :row 21))
+            ,(make-posn :col 18 :row 8) "\e[M!,.")
+           ((mouse-movement ,(make-posn :col 93 :row 54))
+            ,(make-posn :col 29 :row 38) "\e[M@a1")
+           ((down-mouse-3 ,(make-posn :col 92 :row 63))
+            ,(make-posn :col 32 :row 38) "\e[M\"]:")
+           ((mouse-movement ,(make-posn :col 8 :row 92))
+            ,(make-posn :col 3 :row 34) "\e[M@&[")
+           ((mouse-1 ,(make-posn :col 93 :row 21))
+            ,(make-posn :col 0 :row 0) "\e[M#~6")
+           ((mouse-movement ,(make-posn :col 29 :row 74))
+            ,(make-posn :col 7 :row 64) "\e[MA7+")
+           ((mouse-2 ,(make-posn :col 28 :row 92))
+            ,(make-posn :col 23 :row 29) "\e[M#&`")
+           ((mouse-movement ,(make-posn :col 75 :row 36))
+            ,(make-posn :col 75 :row 19) "\e[MB!2")
+           ((mouse-3 ,(make-posn :col 36 :row 76))
+            ,(make-posn :col 17 :row 67) "\e[M#4*")
+           ((mouse-movement ,(make-posn :col 94 :row 58))
+            ,(make-posn :col 54 :row 28) "\e[MCI?")
+           ((mouse-movement ,(make-posn :col 97 :row 79))
+            ,(make-posn :col 46 :row 69) "\e[MCT+")
+           ((mouse-movement ,(make-posn :col 34 :row 76))
+            ,(make-posn :col 28 :row 29) "\e[MC'P")))
+
+        ;; Mouse mode disabled.
+        ;; Disabling any mouse mode, either enabled or not, should
+        ;; disable mouse.
+        (output "\e[?9l")
+        (should (eq mouse-mode nil))
+        (check
+         `(((mouse-1 ,(make-posn)) nil "")
+           ((mouse-2 ,(make-posn)) ,(make-posn) "")
+           ((mouse-3 ,(make-posn :col 8 :row 3))
+            ,(make-posn :col 1 :row 1) "")
+           ((mouse-4 ,(make-posn :col 13 :row 4))
+            ,(make-posn :col 5 :row 1) "")
+           ((mouse-movement ,(make-posn :col 90 :row 40))
+            ,(make-posn :col 82 :row 33) "")))))))
+
+(provide 'eat-tests)
+;;; eat-tests.el ends here
diff --git a/eat.el b/eat.el
new file mode 100644
index 0000000000..32f387ff3f
--- /dev/null
+++ b/eat.el
@@ -0,0 +1,6662 @@
+;;; eat.el --- Emulate A Terminal, in a region, a buffer and in Eshell -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Akib Azmain Turja.
+
+;; Author: Akib Azmain Turja <akib@disroot.org>
+;; Created: 2022-08-15
+;; Version: 0.1snapshot
+;; Package-Requires: ((emacs "28.1"))
+;; Keywords: terminals processes
+;; Homepage: https://codeberg.org/akib/emacs-eat
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; For a full copy of the GNU General Public License
+;; see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Eat's name self-explainary, it stands for "Emulate A Terminal".
+;; Eat is a terminal emulator.  It can run most (if not all)
+;; full-screen terminal programs, including Emacs.
+
+;; It is pretty fast, more than three times faster than Term, despite
+;; being implemented entirely in Emacs Lisp.  So fast that you can
+;; comfortably run Emacs inside Eat, or even use your Emacs as a
+;; terminal multiplexer.
+
+;; It has many feature that other Emacs terminal emulator still don't
+;; have, for example complete mouse support.
+
+;; It flickers less than other Emacs terminal emulator, so you get
+;; more performance and a smooth experience.
+
+;; To start Eat, run M-x eat.  Eat has three keybinding modes:
+
+;;   * "emacs" mode: No special keybinding, except the following:
+
+;;       * `C-c' `C-s': Switch to semi-char mode.
+;;       * `C-c' `C-j': Switch to char mode.
+;;       * `C-c' `C-k': Kill process.
+
+;;   * "semi-char" mode: Most keys are bound to send the key to the
+;;     terminal, except the following keys: `C-\', `C-c', `C-x',
+;;     `C-g', `C-h', `C-M-c', `C-u', `M-x', `M-:', `M-!', `M-&'.  The
+;;     following special keybinding are available:
+
+;;       * `C-q': Send next key to the terminal.
+;;       * `C-y': Like `yank', but send the text to the terminal.
+;;       * `M-y': Like `yank-pop', but send the text to the terminal.
+;;       * `C-c' `C-k': Kill process.
+
+;;   * "char" mode: All supported keys are bound to send the key to
+;;     the terminal, except `C-M-m' or `M-RET', which is bound to
+;;     switch to semi-char mode.
+
+;; If you like Eshell, then there is a good news for you.  Eat
+;; integrates with Eshell.  Eat has two global minor modes for Eshell:
+
+;;   * `eat-eshell-visual-command-mode': Run visual commands with Eat
+;;     instead of Term.
+
+;;   * `eat-eshell-mode': Run Eat inside Eshell.  After enabling this,
+;;     you can run full-screen terminal programs directly in Eshell.
+;;     You have three keybinding modes here too, except that `C-c'
+;;     `C-k' is not special (i.e. not bound by Eat) in "emacs" mode
+;;     and "line" mode.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'ansi-color)
+(require 'shell)
+
+
+;;;; User Options.
+
+(defgroup eat nil
+  "Emulate A Terminal."
+  :group 'processes
+  :group 'terminals
+  :link '(url-link "https://codeberg.org/akib/emacs-eat";))
+
+(defgroup eat-term nil
+  "Eat terminal emulator."
+  :group 'eat)
+
+(defgroup eat-ui nil
+  "Eat user interface."
+  :group 'eat)
+
+(defgroup eat-eshell nil
+  "Eat Eshell integration."
+  :group 'eat)
+
+(defcustom eat-buffer-name "*eat*"
+  "The basename used for Eat buffers.
+
+This is the default name used when running Eat."
+  :type 'string
+  :group 'eat-ui)
+
+(defcustom eat-kill-buffer-on-exit nil
+  "Non-nil means automatically kill Eat buffer when process exits."
+  :type 'boolean
+  :group 'eat-ui)
+
+(defcustom eat-term-scrollback-size 131072 ; 128 K
+  "Size of scrollback area in characters.  nil means unlimited."
+  :type '(choice integer (const nil))
+  :group 'eat-term
+  :group 'eat-ui)
+
+(defcustom eat-enable-kill-from-terminal t
+  "Non-nil means allow terminal program to add text to `kill-ring'.
+
+When non-nil, terminal program can send special escape sequence to add
+some text to `kill-ring'."
+  :type 'boolean
+  :group 'eat-ui
+  :group 'eat-eshell)
+
+(defcustom eat-enable-yank-to-terminal nil
+  "Non-nil means allow terminal program to get text from `kill-ring'.
+
+When non-nil, terminal program can get killed text from `kill-ring'.
+This is left disabled for security reasons."
+  :type 'boolean
+  :group 'eat-ui
+  :group 'eat-eshell)
+
+(defconst eat--cursor-type-value-type
+  (let ((cur-type
+         '(choice
+           (const :tag "Frame default" t)
+           (const :tag "Filled box" box)
+           (cons :tag "Box with specified size" (const box) integer)
+           (const :tag "Hollow cursor" hollow)
+           (const :tag "Vertical bar" bar)
+           (cons :tag "Vertical bar with specified height" (const bar)
+                 integer)
+           (const :tag "Horizontal bar" hbar)
+           (cons :tag "Horizontal bar with specified width"
+                 (const hbar) integer)
+           (const :tag "None " nil))))
+    `(list
+      ,cur-type
+      (choice
+       (const :tag "No blinking" nil)
+       (number :tag "Blinking frequency"))
+      ,cur-type))
+  "Custom type specification for Eat's cursor type variables.")
+
+(defcustom eat-default-cursor-type
+  `(,(default-value 'cursor-type) nil nil)
+  "Cursor to use in Eat buffer.
+
+The value is a list of form (CURSOR-ON BLINKING-FREQUENCY CURSOR-OFF).
+
+When the cursor is on, CURSOR-ON is used as `cursor-type', which see.
+BLINKING-FREQUENCY is the blinking frequency of cursor's blinking.
+When the cursor is off, CURSOR-OFF is used as `cursor-type'.  This
+should be nil when cursor is not blinking."
+  :type eat--cursor-type-value-type
+  :group 'eat-ui
+  :group 'eat-ehell)
+
+(defcustom eat-invisible-cursor-type '(nil nil nil)
+  "Invisible cursor to use in Eat buffer.
+
+The value is a list of form (CURSOR-ON BLINKING-FREQUENCY CURSOR-OFF).
+
+When the cursor is on, CURSOR-ON is used as `cursor-type', which see.
+BLINKING-FREQUENCY is the blinking frequency of cursor's blinking.
+When the cursor is off, CURSOR-OFF is used as `cursor-type'.  This
+should be nil when cursor is not blinking."
+  :type eat--cursor-type-value-type
+  :group 'eat-ui
+  :group 'eat-ehell)
+
+(defcustom eat-very-visible-cursor-type
+  `(,(default-value 'cursor-type) 2 hollow)
+  "Very visible cursor to use in Eat buffer.
+
+When the cursor is invisible, the car of the value is used as
+`cursor-type', which see.  The cdr of the value, when non-nil, is the
+blinking frequency of cursor."
+  :type eat--cursor-type-value-type
+  :group 'eat-ui
+  :group 'eat-ehell)
+
+(defcustom eat-minimum-latency 0.008
+  "Minimum display latency in seconds.
+
+Lowering it too much may cause (or increase) flickering and decrease
+performance due to too many redisplays.  Increasing it too much will
+cause the terminal to feel less responsive.  Try to increase this
+value if the terminal flickers."
+  :type 'number
+  :group 'eat-ui
+  :group 'eat-ehell)
+
+(defcustom eat-maximum-latency 0.033
+  "Minimum display latency in seconds.
+
+Increasing it too much may make the terminal feel less responsive in
+case of huge burst of output.  Try to increase this value if the
+terminal flickers.  Try to lower the value if the terminal feels less
+responsive."
+  :type 'number
+  :group 'eat-ui
+  :group 'eat-ehell)
+
+(defcustom eat-term-name #'eat-term-get-suitable-term-name
+  "Value for the `TERM' environment variable.
+
+The value can also be a function.  In that case, the function is
+called without any argument and the return value is used as the value.
+For example, this can set to `eat-term-get-suitable-term-name' to set
+the value according to the number of colors supported by the current
+display.
+
+This value is used by terminal programs to identify the terminal."
+  :type '(choice
+          (string :tag "Value")
+          (const :tag "Automatic" eat-term-get-suitable-term-name)
+          (function :tag "Function"))
+  :group 'eat-term)
+
+;; Upgrading Eat causes `eat-term-terminfo-directory' to be outdated,
+;; so update it if not modified by user (or something else).
+(defvar eat--install-path nil
+  "Path to directory where Eat is installed.")
+
+(defvar eat-term-terminfo-directory)
+(let ((old-install-path eat--install-path))
+  (setq eat--install-path
+        (copy-sequence
+         (file-name-directory (or load-file-name
+                                  buffer-file-name))))
+
+  (defcustom eat-term-terminfo-directory eat--install-path
+    "Directory where require terminfo databases can be found.
+
+This value is used by terminal programs to find the terminfo databases
+that describe the capabilities of the terminal."
+    :type 'directory
+    :group 'eat-term)
+
+  (when (eq eat-term-terminfo-directory old-install-path)
+    (setq eat-term-terminfo-directory eat--install-path)))
+
+(defcustom eat-term-inside-emacs (format "%s,eat" emacs-version)
+  "Value for the `INSIDE_EMACS' environment variable."
+  :type 'string
+  :group 'eat-term)
+
+(defcustom eat-enable-blinking-text nil
+  "Non-nil means enable blinking of text with blink attribute.
+
+When non-nil, enable `eat-blink-mode' to enable blinking of text with
+blink attribute by default.  You manually toggle `eat-blink-mode' to
+toggle this behavior buffer-locally."
+  :type 'boolean
+  :group 'eat-ui
+  :group 'eat-eshell)
+
+(defcustom eat-slow-blink-frequency 2
+  "Frequency of blinking of slowly text.
+
+This has an effect only if `eat-blink-mode' is enabled."
+  :type 'number
+  :group 'eat-ui)
+
+(defcustom eat-fast-blink-frequency 3
+  "Frequency of blinking of rapidly text.
+
+This has an effect only if `eat-blink-mode' is enabled."
+  :type 'number
+  :group 'eat-ui)
+
+(defcustom eat-enable-alternative-display t
+  "Non-nil means enable alternative display.
+
+Full screen programs often use alternative display to keep old
+contents on display unaltered."
+  :type 'boolean
+  :group 'eat-term)
+
+(defcustom eat-enable-mouse t
+  "Non-nil means enable mouse support.
+
+When non-nil, terminal programs can receive mouse events from Emacs."
+  :type 'boolean
+  :group 'eat-ui)
+
+(defcustom eat-input-chunk-size 1024
+  "Maximum size of chunk of data send at once.
+
+Long inputs send to Eat processes are broken up into chunks of this
+size.
+
+If your process is choking on big inputs, try lowering the value."
+  :type 'integer
+  :group 'eat-ui)
+
+(defface eat-term-bold '((t :inherit bold))
+  "Face used to render bold text."
+  :group 'eat-term)
+
+(defface eat-term-faint '((t :weight light))
+  "Face used to render faint text."
+  :group 'eat-term)
+
+(defface eat-term-italic '((t :inherit italic))
+  "Face used to render italic text."
+  :group 'eat-term)
+
+(defface eat-term-slow-blink '((t :inverse-video t))
+  "Face used to render slowly blinking text."
+  :group 'eat-term)
+
+(defface eat-term-fast-blink '((t :inverse-video t))
+  "Face used to render rapidly blinking text."
+  :group 'eat-term)
+
+(defface eat-term-color-0
+  '((t :inherit ansi-color-black))
+  "Face used to render black color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-black 'face-alias 'eat-term-color-0)
+
+(defface eat-term-color-1
+  '((t :inherit ansi-color-red))
+  "Face used to render red color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-red 'face-alias 'eat-term-color-1)
+
+(defface eat-term-color-2
+  '((t :inherit ansi-color-green))
+  "Face used to render green color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-green 'face-alias 'eat-term-color-2)
+
+(defface eat-term-color-3
+  '((t :inherit ansi-color-yellow))
+  "Face used to render yellow color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-yellow 'face-alias 'eat-term-color-3)
+
+(defface eat-term-color-4
+  '((t :inherit ansi-color-blue))
+  "Face used to render blue color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-blue 'face-alias 'eat-term-color-4)
+
+(defface eat-term-color-5
+  '((t :inherit ansi-color-magenta))
+  "Face used to render magenta color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-magenta 'face-alias 'eat-term-color-5)
+
+(defface eat-term-color-6
+  '((t :inherit ansi-color-cyan))
+  "Face used to render cyan color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-cyan 'face-alias 'eat-term-color-6)
+
+(defface eat-term-color-7
+  '((t :inherit ansi-color-white))
+  "Face used to render white color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-white 'face-alias 'eat-term-color-7)
+
+(defface eat-term-color-8
+  '((t :inherit ansi-color-bright-black))
+  "Face used to render bright black color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-black 'face-alias 'eat-term-color-8)
+
+(defface eat-term-color-9
+  '((t :inherit ansi-color-bright-red))
+  "Face used to render bright red color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-red 'face-alias 'eat-term-color-9)
+
+(defface eat-term-color-10
+  '((t :inherit ansi-color-bright-green))
+  "Face used to render bright green color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-green 'face-alias 'eat-term-color-10)
+
+(defface eat-term-color-11
+  '((t :inherit ansi-color-bright-yellow))
+  "Face used to render bright yellow color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-yellow 'face-alias 'eat-term-color-11)
+
+(defface eat-term-color-12
+  '((t :inherit ansi-color-bright-blue))
+  "Face used to render bright blue color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-blue 'face-alias 'eat-term-color-12)
+
+(defface eat-term-color-13
+  '((t :inherit ansi-color-bright-magenta))
+  "Face used to render bright magenta color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-magenta 'face-alias 'eat-term-color-13)
+
+(defface eat-term-color-14
+  '((t :inherit ansi-color-bright-cyan))
+  "Face used to render bright cyan color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-cyan 'face-alias 'eat-term-color-14)
+
+(defface eat-term-color-15
+  '((t :inherit ansi-color-bright-white))
+  "Face used to render bright white color text."
+  :group 'eat-term)
+
+(put 'eat-term-color-bright-white 'face-alias 'eat-term-color-15)
+
+(defface eat-term-color-16
+  '((t :foreground "#000000" :background "#000000"))
+  "Face used to render text with 16th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-17
+  '((t :foreground "#00005F" :background "#00005F"))
+  "Face used to render text with 17th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-18
+  '((t :foreground "#000087" :background "#000087"))
+  "Face used to render text with 18th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-19
+  '((t :foreground "#0000AF" :background "#0000AF"))
+  "Face used to render text with 19th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-20
+  '((t :foreground "#0000D7" :background "#0000D7"))
+  "Face used to render text with 20th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-21
+  '((t :foreground "#0000FF" :background "#0000FF"))
+  "Face used to render text with 21th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-22
+  '((t :foreground "#005F00" :background "#005F00"))
+  "Face used to render text with 22th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-23
+  '((t :foreground "#005F5F" :background "#005F5F"))
+  "Face used to render text with 23th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-24
+  '((t :foreground "#005F87" :background "#005F87"))
+  "Face used to render text with 24th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-25
+  '((t :foreground "#005FAF" :background "#005FAF"))
+  "Face used to render text with 25th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-26
+  '((t :foreground "#005FD7" :background "#005FD7"))
+  "Face used to render text with 26th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-27
+  '((t :foreground "#005FFF" :background "#005FFF"))
+  "Face used to render text with 27th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-28
+  '((t :foreground "#008700" :background "#008700"))
+  "Face used to render text with 28th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-29
+  '((t :foreground "#00875F" :background "#00875F"))
+  "Face used to render text with 29th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-30
+  '((t :foreground "#008787" :background "#008787"))
+  "Face used to render text with 30th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-31
+  '((t :foreground "#0087AF" :background "#0087AF"))
+  "Face used to render text with 31th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-32
+  '((t :foreground "#0087D7" :background "#0087D7"))
+  "Face used to render text with 32th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-33
+  '((t :foreground "#0087FF" :background "#0087FF"))
+  "Face used to render text with 33th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-34
+  '((t :foreground "#00AF00" :background "#00AF00"))
+  "Face used to render text with 34th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-35
+  '((t :foreground "#00AF5F" :background "#00AF5F"))
+  "Face used to render text with 35th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-36
+  '((t :foreground "#00AF87" :background "#00AF87"))
+  "Face used to render text with 36th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-37
+  '((t :foreground "#00AFAF" :background "#00AFAF"))
+  "Face used to render text with 37th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-38
+  '((t :foreground "#00AFD7" :background "#00AFD7"))
+  "Face used to render text with 38th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-39
+  '((t :foreground "#00AFFF" :background "#00AFFF"))
+  "Face used to render text with 39th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-40
+  '((t :foreground "#00D700" :background "#00D700"))
+  "Face used to render text with 40th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-41
+  '((t :foreground "#00D75F" :background "#00D75F"))
+  "Face used to render text with 41th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-42
+  '((t :foreground "#00D787" :background "#00D787"))
+  "Face used to render text with 42th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-43
+  '((t :foreground "#00D7AF" :background "#00D7AF"))
+  "Face used to render text with 43th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-44
+  '((t :foreground "#00D7D7" :background "#00D7D7"))
+  "Face used to render text with 44th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-45
+  '((t :foreground "#00D7FF" :background "#00D7FF"))
+  "Face used to render text with 45th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-46
+  '((t :foreground "#00FF00" :background "#00FF00"))
+  "Face used to render text with 46th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-47
+  '((t :foreground "#00FF5F" :background "#00FF5F"))
+  "Face used to render text with 47th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-48
+  '((t :foreground "#00FF87" :background "#00FF87"))
+  "Face used to render text with 48th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-49
+  '((t :foreground "#00FFAF" :background "#00FFAF"))
+  "Face used to render text with 49th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-50
+  '((t :foreground "#00FFD7" :background "#00FFD7"))
+  "Face used to render text with 50th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-51
+  '((t :foreground "#00FFFF" :background "#00FFFF"))
+  "Face used to render text with 51th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-52
+  '((t :foreground "#5F0000" :background "#5F0000"))
+  "Face used to render text with 52th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-53
+  '((t :foreground "#5F005F" :background "#5F005F"))
+  "Face used to render text with 53th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-54
+  '((t :foreground "#5F0087" :background "#5F0087"))
+  "Face used to render text with 54th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-55
+  '((t :foreground "#5F00AF" :background "#5F00AF"))
+  "Face used to render text with 55th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-56
+  '((t :foreground "#5F00D7" :background "#5F00D7"))
+  "Face used to render text with 56th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-57
+  '((t :foreground "#5F00FF" :background "#5F00FF"))
+  "Face used to render text with 57th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-58
+  '((t :foreground "#5F5F00" :background "#5F5F00"))
+  "Face used to render text with 58th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-59
+  '((t :foreground "#5F5F5F" :background "#5F5F5F"))
+  "Face used to render text with 59th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-60
+  '((t :foreground "#5F5F87" :background "#5F5F87"))
+  "Face used to render text with 60th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-61
+  '((t :foreground "#5F5FAF" :background "#5F5FAF"))
+  "Face used to render text with 61th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-62
+  '((t :foreground "#5F5FD7" :background "#5F5FD7"))
+  "Face used to render text with 62th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-63
+  '((t :foreground "#5F5FFF" :background "#5F5FFF"))
+  "Face used to render text with 63th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-64
+  '((t :foreground "#5F8700" :background "#5F8700"))
+  "Face used to render text with 64th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-65
+  '((t :foreground "#5F875F" :background "#5F875F"))
+  "Face used to render text with 65th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-66
+  '((t :foreground "#5F8787" :background "#5F8787"))
+  "Face used to render text with 66th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-67
+  '((t :foreground "#5F87AF" :background "#5F87AF"))
+  "Face used to render text with 67th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-68
+  '((t :foreground "#5F87D7" :background "#5F87D7"))
+  "Face used to render text with 68th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-69
+  '((t :foreground "#5F87FF" :background "#5F87FF"))
+  "Face used to render text with 69th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-70
+  '((t :foreground "#5FAF00" :background "#5FAF00"))
+  "Face used to render text with 70th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-71
+  '((t :foreground "#5FAF5F" :background "#5FAF5F"))
+  "Face used to render text with 71th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-72
+  '((t :foreground "#5FAF87" :background "#5FAF87"))
+  "Face used to render text with 72th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-73
+  '((t :foreground "#5FAFAF" :background "#5FAFAF"))
+  "Face used to render text with 73th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-74
+  '((t :foreground "#5FAFD7" :background "#5FAFD7"))
+  "Face used to render text with 74th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-75
+  '((t :foreground "#5FAFFF" :background "#5FAFFF"))
+  "Face used to render text with 75th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-76
+  '((t :foreground "#5FD700" :background "#5FD700"))
+  "Face used to render text with 76th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-77
+  '((t :foreground "#5FD75F" :background "#5FD75F"))
+  "Face used to render text with 77th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-78
+  '((t :foreground "#5FD787" :background "#5FD787"))
+  "Face used to render text with 78th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-79
+  '((t :foreground "#5FD7AF" :background "#5FD7AF"))
+  "Face used to render text with 79th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-80
+  '((t :foreground "#5FD7D7" :background "#5FD7D7"))
+  "Face used to render text with 80th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-81
+  '((t :foreground "#5FD7FF" :background "#5FD7FF"))
+  "Face used to render text with 81th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-82
+  '((t :foreground "#5FFF00" :background "#5FFF00"))
+  "Face used to render text with 82th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-83
+  '((t :foreground "#5FFF5F" :background "#5FFF5F"))
+  "Face used to render text with 83th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-84
+  '((t :foreground "#5FFF87" :background "#5FFF87"))
+  "Face used to render text with 84th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-85
+  '((t :foreground "#5FFFAF" :background "#5FFFAF"))
+  "Face used to render text with 85th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-86
+  '((t :foreground "#5FFFD7" :background "#5FFFD7"))
+  "Face used to render text with 86th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-87
+  '((t :foreground "#5FFFFF" :background "#5FFFFF"))
+  "Face used to render text with 87th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-88
+  '((t :foreground "#870000" :background "#870000"))
+  "Face used to render text with 88th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-89
+  '((t :foreground "#87005F" :background "#87005F"))
+  "Face used to render text with 89th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-90
+  '((t :foreground "#870087" :background "#870087"))
+  "Face used to render text with 90th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-91
+  '((t :foreground "#8700AF" :background "#8700AF"))
+  "Face used to render text with 91th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-92
+  '((t :foreground "#8700D7" :background "#8700D7"))
+  "Face used to render text with 92th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-93
+  '((t :foreground "#8700FF" :background "#8700FF"))
+  "Face used to render text with 93th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-94
+  '((t :foreground "#875F00" :background "#875F00"))
+  "Face used to render text with 94th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-95
+  '((t :foreground "#875F5F" :background "#875F5F"))
+  "Face used to render text with 95th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-96
+  '((t :foreground "#875F87" :background "#875F87"))
+  "Face used to render text with 96th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-97
+  '((t :foreground "#875FAF" :background "#875FAF"))
+  "Face used to render text with 97th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-98
+  '((t :foreground "#875FD7" :background "#875FD7"))
+  "Face used to render text with 98th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-99
+  '((t :foreground "#875FFF" :background "#875FFF"))
+  "Face used to render text with 99th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-100
+  '((t :foreground "#878700" :background "#878700"))
+  "Face used to render text with 100th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-101
+  '((t :foreground "#87875F" :background "#87875F"))
+  "Face used to render text with 101th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-102
+  '((t :foreground "#878787" :background "#878787"))
+  "Face used to render text with 102th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-103
+  '((t :foreground "#8787AF" :background "#8787AF"))
+  "Face used to render text with 103th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-104
+  '((t :foreground "#8787D7" :background "#8787D7"))
+  "Face used to render text with 104th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-105
+  '((t :foreground "#8787FF" :background "#8787FF"))
+  "Face used to render text with 105th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-106
+  '((t :foreground "#87AF00" :background "#87AF00"))
+  "Face used to render text with 106th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-107
+  '((t :foreground "#87AF5F" :background "#87AF5F"))
+  "Face used to render text with 107th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-108
+  '((t :foreground "#87AF87" :background "#87AF87"))
+  "Face used to render text with 108th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-109
+  '((t :foreground "#87AFAF" :background "#87AFAF"))
+  "Face used to render text with 109th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-110
+  '((t :foreground "#87AFD7" :background "#87AFD7"))
+  "Face used to render text with 110th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-111
+  '((t :foreground "#87AFFF" :background "#87AFFF"))
+  "Face used to render text with 111th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-112
+  '((t :foreground "#87D700" :background "#87D700"))
+  "Face used to render text with 112th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-113
+  '((t :foreground "#87D75F" :background "#87D75F"))
+  "Face used to render text with 113th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-114
+  '((t :foreground "#87D787" :background "#87D787"))
+  "Face used to render text with 114th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-115
+  '((t :foreground "#87D7AF" :background "#87D7AF"))
+  "Face used to render text with 115th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-116
+  '((t :foreground "#87D7D7" :background "#87D7D7"))
+  "Face used to render text with 116th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-117
+  '((t :foreground "#87D7FF" :background "#87D7FF"))
+  "Face used to render text with 117th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-118
+  '((t :foreground "#87FF00" :background "#87FF00"))
+  "Face used to render text with 118th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-119
+  '((t :foreground "#87FF5F" :background "#87FF5F"))
+  "Face used to render text with 119th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-120
+  '((t :foreground "#87FF87" :background "#87FF87"))
+  "Face used to render text with 120th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-121
+  '((t :foreground "#87FFAF" :background "#87FFAF"))
+  "Face used to render text with 121th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-122
+  '((t :foreground "#87FFD7" :background "#87FFD7"))
+  "Face used to render text with 122th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-123
+  '((t :foreground "#87FFFF" :background "#87FFFF"))
+  "Face used to render text with 123th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-124
+  '((t :foreground "#AF0000" :background "#AF0000"))
+  "Face used to render text with 124th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-125
+  '((t :foreground "#AF005F" :background "#AF005F"))
+  "Face used to render text with 125th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-126
+  '((t :foreground "#AF0087" :background "#AF0087"))
+  "Face used to render text with 126th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-127
+  '((t :foreground "#AF00AF" :background "#AF00AF"))
+  "Face used to render text with 127th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-128
+  '((t :foreground "#AF00D7" :background "#AF00D7"))
+  "Face used to render text with 128th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-129
+  '((t :foreground "#AF00FF" :background "#AF00FF"))
+  "Face used to render text with 129th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-130
+  '((t :foreground "#AF5F00" :background "#AF5F00"))
+  "Face used to render text with 130th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-131
+  '((t :foreground "#AF5F5F" :background "#AF5F5F"))
+  "Face used to render text with 131th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-132
+  '((t :foreground "#AF5F87" :background "#AF5F87"))
+  "Face used to render text with 132th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-133
+  '((t :foreground "#AF5FAF" :background "#AF5FAF"))
+  "Face used to render text with 133th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-134
+  '((t :foreground "#AF5FD7" :background "#AF5FD7"))
+  "Face used to render text with 134th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-135
+  '((t :foreground "#AF5FFF" :background "#AF5FFF"))
+  "Face used to render text with 135th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-136
+  '((t :foreground "#AF8700" :background "#AF8700"))
+  "Face used to render text with 136th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-137
+  '((t :foreground "#AF875F" :background "#AF875F"))
+  "Face used to render text with 137th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-138
+  '((t :foreground "#AF8787" :background "#AF8787"))
+  "Face used to render text with 138th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-139
+  '((t :foreground "#AF87AF" :background "#AF87AF"))
+  "Face used to render text with 139th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-140
+  '((t :foreground "#AF87D7" :background "#AF87D7"))
+  "Face used to render text with 140th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-141
+  '((t :foreground "#AF87FF" :background "#AF87FF"))
+  "Face used to render text with 141th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-142
+  '((t :foreground "#AFAF00" :background "#AFAF00"))
+  "Face used to render text with 142th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-143
+  '((t :foreground "#AFAF5F" :background "#AFAF5F"))
+  "Face used to render text with 143th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-144
+  '((t :foreground "#AFAF87" :background "#AFAF87"))
+  "Face used to render text with 144th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-145
+  '((t :foreground "#AFAFAF" :background "#AFAFAF"))
+  "Face used to render text with 145th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-146
+  '((t :foreground "#AFAFD7" :background "#AFAFD7"))
+  "Face used to render text with 146th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-147
+  '((t :foreground "#AFAFFF" :background "#AFAFFF"))
+  "Face used to render text with 147th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-148
+  '((t :foreground "#AFD700" :background "#AFD700"))
+  "Face used to render text with 148th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-149
+  '((t :foreground "#AFD75F" :background "#AFD75F"))
+  "Face used to render text with 149th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-150
+  '((t :foreground "#AFD787" :background "#AFD787"))
+  "Face used to render text with 150th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-151
+  '((t :foreground "#AFD7AF" :background "#AFD7AF"))
+  "Face used to render text with 151th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-152
+  '((t :foreground "#AFD7D7" :background "#AFD7D7"))
+  "Face used to render text with 152th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-153
+  '((t :foreground "#AFD7FF" :background "#AFD7FF"))
+  "Face used to render text with 153th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-154
+  '((t :foreground "#AFFF00" :background "#AFFF00"))
+  "Face used to render text with 154th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-155
+  '((t :foreground "#AFFF5F" :background "#AFFF5F"))
+  "Face used to render text with 155th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-156
+  '((t :foreground "#AFFF87" :background "#AFFF87"))
+  "Face used to render text with 156th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-157
+  '((t :foreground "#AFFFAF" :background "#AFFFAF"))
+  "Face used to render text with 157th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-158
+  '((t :foreground "#AFFFD7" :background "#AFFFD7"))
+  "Face used to render text with 158th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-159
+  '((t :foreground "#AFFFFF" :background "#AFFFFF"))
+  "Face used to render text with 159th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-160
+  '((t :foreground "#D70000" :background "#D70000"))
+  "Face used to render text with 160th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-161
+  '((t :foreground "#D7005F" :background "#D7005F"))
+  "Face used to render text with 161th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-162
+  '((t :foreground "#D70087" :background "#D70087"))
+  "Face used to render text with 162th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-163
+  '((t :foreground "#D700AF" :background "#D700AF"))
+  "Face used to render text with 163th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-164
+  '((t :foreground "#D700D7" :background "#D700D7"))
+  "Face used to render text with 164th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-165
+  '((t :foreground "#D700FF" :background "#D700FF"))
+  "Face used to render text with 165th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-166
+  '((t :foreground "#D75F00" :background "#D75F00"))
+  "Face used to render text with 166th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-167
+  '((t :foreground "#D75F5F" :background "#D75F5F"))
+  "Face used to render text with 167th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-168
+  '((t :foreground "#D75F87" :background "#D75F87"))
+  "Face used to render text with 168th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-169
+  '((t :foreground "#D75FAF" :background "#D75FAF"))
+  "Face used to render text with 169th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-170
+  '((t :foreground "#D75FD7" :background "#D75FD7"))
+  "Face used to render text with 170th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-171
+  '((t :foreground "#D75FFF" :background "#D75FFF"))
+  "Face used to render text with 171th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-172
+  '((t :foreground "#D78700" :background "#D78700"))
+  "Face used to render text with 172th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-173
+  '((t :foreground "#D7875F" :background "#D7875F"))
+  "Face used to render text with 173th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-174
+  '((t :foreground "#D78787" :background "#D78787"))
+  "Face used to render text with 174th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-175
+  '((t :foreground "#D787AF" :background "#D787AF"))
+  "Face used to render text with 175th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-176
+  '((t :foreground "#D787D7" :background "#D787D7"))
+  "Face used to render text with 176th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-177
+  '((t :foreground "#D787FF" :background "#D787FF"))
+  "Face used to render text with 177th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-178
+  '((t :foreground "#D7AF00" :background "#D7AF00"))
+  "Face used to render text with 178th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-179
+  '((t :foreground "#D7AF5F" :background "#D7AF5F"))
+  "Face used to render text with 179th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-180
+  '((t :foreground "#D7AF87" :background "#D7AF87"))
+  "Face used to render text with 180th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-181
+  '((t :foreground "#D7AFAF" :background "#D7AFAF"))
+  "Face used to render text with 181th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-182
+  '((t :foreground "#D7AFD7" :background "#D7AFD7"))
+  "Face used to render text with 182th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-183
+  '((t :foreground "#D7AFFF" :background "#D7AFFF"))
+  "Face used to render text with 183th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-184
+  '((t :foreground "#D7D700" :background "#D7D700"))
+  "Face used to render text with 184th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-185
+  '((t :foreground "#D7D75F" :background "#D7D75F"))
+  "Face used to render text with 185th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-186
+  '((t :foreground "#D7D787" :background "#D7D787"))
+  "Face used to render text with 186th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-187
+  '((t :foreground "#D7D7AF" :background "#D7D7AF"))
+  "Face used to render text with 187th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-188
+  '((t :foreground "#D7D7D7" :background "#D7D7D7"))
+  "Face used to render text with 188th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-189
+  '((t :foreground "#D7D7FF" :background "#D7D7FF"))
+  "Face used to render text with 189th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-190
+  '((t :foreground "#D7FF00" :background "#D7FF00"))
+  "Face used to render text with 190th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-191
+  '((t :foreground "#D7FF5F" :background "#D7FF5F"))
+  "Face used to render text with 191th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-192
+  '((t :foreground "#D7FF87" :background "#D7FF87"))
+  "Face used to render text with 192th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-193
+  '((t :foreground "#D7FFAF" :background "#D7FFAF"))
+  "Face used to render text with 193th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-194
+  '((t :foreground "#D7FFD7" :background "#D7FFD7"))
+  "Face used to render text with 194th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-195
+  '((t :foreground "#D7FFFF" :background "#D7FFFF"))
+  "Face used to render text with 195th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-196
+  '((t :foreground "#FF0000" :background "#FF0000"))
+  "Face used to render text with 196th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-197
+  '((t :foreground "#FF005F" :background "#FF005F"))
+  "Face used to render text with 197th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-198
+  '((t :foreground "#FF0087" :background "#FF0087"))
+  "Face used to render text with 198th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-199
+  '((t :foreground "#FF00AF" :background "#FF00AF"))
+  "Face used to render text with 199th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-200
+  '((t :foreground "#FF00D7" :background "#FF00D7"))
+  "Face used to render text with 200th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-201
+  '((t :foreground "#FF00FF" :background "#FF00FF"))
+  "Face used to render text with 201th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-202
+  '((t :foreground "#FF5F00" :background "#FF5F00"))
+  "Face used to render text with 202th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-203
+  '((t :foreground "#FF5F5F" :background "#FF5F5F"))
+  "Face used to render text with 203th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-204
+  '((t :foreground "#FF5F87" :background "#FF5F87"))
+  "Face used to render text with 204th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-205
+  '((t :foreground "#FF5FAF" :background "#FF5FAF"))
+  "Face used to render text with 205th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-206
+  '((t :foreground "#FF5FD7" :background "#FF5FD7"))
+  "Face used to render text with 206th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-207
+  '((t :foreground "#FF5FFF" :background "#FF5FFF"))
+  "Face used to render text with 207th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-208
+  '((t :foreground "#FF8700" :background "#FF8700"))
+  "Face used to render text with 208th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-209
+  '((t :foreground "#FF875F" :background "#FF875F"))
+  "Face used to render text with 209th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-210
+  '((t :foreground "#FF8787" :background "#FF8787"))
+  "Face used to render text with 210th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-211
+  '((t :foreground "#FF87AF" :background "#FF87AF"))
+  "Face used to render text with 211th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-212
+  '((t :foreground "#FF87D7" :background "#FF87D7"))
+  "Face used to render text with 212th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-213
+  '((t :foreground "#FF87FF" :background "#FF87FF"))
+  "Face used to render text with 213th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-214
+  '((t :foreground "#FFAF00" :background "#FFAF00"))
+  "Face used to render text with 214th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-215
+  '((t :foreground "#FFAF5F" :background "#FFAF5F"))
+  "Face used to render text with 215th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-216
+  '((t :foreground "#FFAF87" :background "#FFAF87"))
+  "Face used to render text with 216th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-217
+  '((t :foreground "#FFAFAF" :background "#FFAFAF"))
+  "Face used to render text with 217th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-218
+  '((t :foreground "#FFAFD7" :background "#FFAFD7"))
+  "Face used to render text with 218th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-219
+  '((t :foreground "#FFAFFF" :background "#FFAFFF"))
+  "Face used to render text with 219th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-220
+  '((t :foreground "#FFD700" :background "#FFD700"))
+  "Face used to render text with 220th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-221
+  '((t :foreground "#FFD75F" :background "#FFD75F"))
+  "Face used to render text with 221th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-222
+  '((t :foreground "#FFD787" :background "#FFD787"))
+  "Face used to render text with 222th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-223
+  '((t :foreground "#FFD7AF" :background "#FFD7AF"))
+  "Face used to render text with 223th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-224
+  '((t :foreground "#FFD7D7" :background "#FFD7D7"))
+  "Face used to render text with 224th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-225
+  '((t :foreground "#FFD7FF" :background "#FFD7FF"))
+  "Face used to render text with 225th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-226
+  '((t :foreground "#FFFF00" :background "#FFFF00"))
+  "Face used to render text with 226th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-227
+  '((t :foreground "#FFFF5F" :background "#FFFF5F"))
+  "Face used to render text with 227th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-228
+  '((t :foreground "#FFFF87" :background "#FFFF87"))
+  "Face used to render text with 228th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-229
+  '((t :foreground "#FFFFAF" :background "#FFFFAF"))
+  "Face used to render text with 229th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-230
+  '((t :foreground "#FFFFD7" :background "#FFFFD7"))
+  "Face used to render text with 230th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-231
+  '((t :foreground "#FFFFFF" :background "#FFFFFF"))
+  "Face used to render text with 231th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-232
+  '((t :foreground "#080808" :background "#080808"))
+  "Face used to render text with 232th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-233
+  '((t :foreground "#121212" :background "#121212"))
+  "Face used to render text with 233th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-234
+  '((t :foreground "#1C1C1C" :background "#1C1C1C"))
+  "Face used to render text with 234th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-235
+  '((t :foreground "#262626" :background "#262626"))
+  "Face used to render text with 235th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-236
+  '((t :foreground "#303030" :background "#303030"))
+  "Face used to render text with 236th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-237
+  '((t :foreground "#3A3A3A" :background "#3A3A3A"))
+  "Face used to render text with 237th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-238
+  '((t :foreground "#444444" :background "#444444"))
+  "Face used to render text with 238th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-239
+  '((t :foreground "#4E4E4E" :background "#4E4E4E"))
+  "Face used to render text with 239th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-240
+  '((t :foreground "#585858" :background "#585858"))
+  "Face used to render text with 240th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-241
+  '((t :foreground "#626262" :background "#626262"))
+  "Face used to render text with 241th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-242
+  '((t :foreground "#6C6C6C" :background "#6C6C6C"))
+  "Face used to render text with 242th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-243
+  '((t :foreground "#767676" :background "#767676"))
+  "Face used to render text with 243th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-244
+  '((t :foreground "#808080" :background "#808080"))
+  "Face used to render text with 244th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-245
+  '((t :foreground "#8A8A8A" :background "#8A8A8A"))
+  "Face used to render text with 245th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-246
+  '((t :foreground "#949494" :background "#949494"))
+  "Face used to render text with 246th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-247
+  '((t :foreground "#9E9E9E" :background "#9E9E9E"))
+  "Face used to render text with 247th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-248
+  '((t :foreground "#A8A8A8" :background "#A8A8A8"))
+  "Face used to render text with 248th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-249
+  '((t :foreground "#B2B2B2" :background "#B2B2B2"))
+  "Face used to render text with 249th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-250
+  '((t :foreground "#BCBCBC" :background "#BCBCBC"))
+  "Face used to render text with 250th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-251
+  '((t :foreground "#C6C6C6" :background "#C6C6C6"))
+  "Face used to render text with 251th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-252
+  '((t :foreground "#D0D0D0" :background "#D0D0D0"))
+  "Face used to render text with 252th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-253
+  '((t :foreground "#DADADA" :background "#DADADA"))
+  "Face used to render text with 253th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-254
+  '((t :foreground "#E4E4E4" :background "#E4E4E4"))
+  "Face used to render text with 254th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-color-255
+  '((t :foreground "#EEEEEE" :background "#EEEEEE"))
+  "Face used to render text with 255th color of 256 color palette."
+  :group 'eat-term)
+
+(defface eat-term-font-0 '((t))
+  "Default font.")
+
+(put 'eat-term-font-default 'face-alias 'eat-term-font-0)
+
+(defface eat-term-font-1 '((t))
+  "Alternative font 1.")
+
+(defface eat-term-font-2 '((t))
+  "Alternative font 2.")
+
+(defface eat-term-font-3 '((t))
+  "Alternative font 3.")
+
+(defface eat-term-font-4 '((t))
+  "Alternative font 4.")
+
+(defface eat-term-font-5 '((t))
+  "Alternative font 5.")
+
+(defface eat-term-font-6 '((t))
+  "Alternative font 6.")
+
+(defface eat-term-font-7 '((t))
+  "Alternative font 7.")
+
+(defface eat-term-font-8 '((t))
+  "Alternative font 8.")
+
+(defface eat-term-font-9 '((t))
+  "Alternative font 9.")
+
+
+;;;; Utility Functions.
+
+(defun eat--t-goto-bol (&optional n)
+  "Go to the beginning of current line.
+
+With optional argument N, go to the beginning of Nth next line if N is
+positive, otherwise go to the beginning of -Nth previous line.  If the
+specified position is before `point-min' or after `point-max', go to
+that point.
+
+Return the number of lines moved.
+
+Treat LINE FEED (?\\n) as the line delimiter."
+  ;; TODO: Comment.
+  (let ((n (or n 0)))
+    (cond
+     ((> n 0)
+      (let ((moved 0))
+        (while (and (< (point) (point-max))
+                    (< moved n))
+          (and (search-forward "\n" nil 'move)
+               (cl-incf moved)))
+        moved))
+     ((<= n 0)
+      (let ((moved 1))
+        (while (and (or (= moved 1)
+                        (< (point-min) (point)))
+                    (< n moved))
+          (cl-decf moved)
+          (and (search-backward "\n" nil 'move)
+               (= moved n)
+               (goto-char (match-end 0))))
+        moved)))))
+
+(defun eat--t-goto-eol (&optional n)
+  "Go to the end of current line.
+
+With optional argument N, go to the end of Nth next line if N is
+positive, otherwise go to the end of -Nth previous line.  If the
+specified position is before `point-min' or after `point-max', go to
+that point.
+
+Return the number of lines moved.
+
+Treat LINE FEED (?\\n) as the line delimiter."
+  ;; TODO: Comment.
+  (let ((n (or n 0)))
+    (cond
+     ((>= n 0)
+      (let ((moved -1))
+        (while (and (or (= moved -1)
+                        (< (point) (point-max)))
+                    (< moved n))
+          (cl-incf moved)
+          (and (search-forward "\n" nil 'move)
+               (= moved n)
+               (goto-char (match-beginning 0))))
+        moved))
+     ((< n 0)
+      (let ((moved 0))
+        (while (and (< (point-min) (point))
+                    (< n moved))
+          (and (search-backward "\n" nil 'move)
+               (cl-decf moved)))
+        moved)))))
+
+(defun eat--t-bol (&optional n)
+  "Return the beginning of current line.
+
+With optional argument N, return a cons cell whose car is the
+beginning of Nth next line and cdr is N, if N is positive, otherwise
+return a cons cell whose car is the beginning of -Nth previous line
+and cdr is N.  If the specified position is before `point-min' or
+after `point-max', return a cons cell whose car is that point and cdr
+is number of lines that point is away from current line.
+
+Treat LINE FEED (?\\n) as the line delimiter."
+  ;; Move to the beginning of line, record the point, and return that
+  ;; point and the distance of that point from current line in lines.
+  (save-excursion
+    (let ((moved (eat--t-goto-bol n)))
+      (cons (point) moved))))
+
+(defun eat--t-eol (&optional n)
+  "Return the end of current line.
+
+With optional argument N, return a cons cell whose car the end of Nth
+next line and cdr is N, if N is positive, otherwise return a cons cell
+whose car is the end of -Nth previous line and cdr in N.  If the
+specified position is before `point-min' or after `point-max', return
+a cons cell whose car is that point and cdr is number of lines that
+point is away from current line.
+
+Treat LINE FEED (?\\n) as the line delimiter."
+  ;; Move to the beginning of line, record the point, and return that
+  ;; point and the distance of that point from current line in lines.
+  (save-excursion
+    (let* ((moved (eat--t-goto-eol n)))
+      (cons (point) moved))))
+
+(defun eat--t-col-motion (n)
+  "Move to Nth next column.
+
+Go to Nth next column if N is positive, otherwise go to -Nth previous
+column.  If the specified position is before `point-min' or after
+`point-max', go to that point.
+
+Return the number of columns moved.
+
+Assume all characters occupy a single column."
+  ;; Record the current position.
+  (let ((point (point)))
+    ;; Move to the new position.
+    (cond
+     ((> n 0)
+      (let ((eol (car (eat--t-eol)))
+            (pos (+ (point) n)))
+        (goto-char (min pos eol))))
+     ((< n 0)
+      (let ((bol (car (eat--t-bol)))
+            (pos (+ (point) n)))
+        (goto-char (max pos bol)))))
+    ;; Return the distance from the previous position.
+    (- (point) point)))
+
+(defun eat--t-current-col ()
+  "Return the current column.
+
+Assume all characters occupy a single column."
+  ;; We assume that that all characters occupy a single column, so a
+  ;; subtraction should work.
+  (- (point) (car (eat--t-bol))))
+
+(defun eat--t-goto-col (n)
+  "Go to column N.
+
+Return the current column after moving point.
+
+Assume all characters occupy a single column."
+  ;; Move to column 0.
+  (eat--t-goto-bol)
+  ;; Now the target column is N characters away.
+  (eat--t-col-motion n))
+
+(defun eat--t-repeated-insert (c n &optional face)
+  "Insert C, N times.
+
+C is a character.  FACE is the face to use, or nil."
+  (let ((str (make-string n c)))
+    (insert (if face (propertize str 'face face) str))))
+
+(defun eat--t-join-long-line (&optional limit)
+  "Join long line once, but don't try to go beyond LIMIT.
+
+For example: \"*foo\\nbar\\nbaz\" is converted to \"foo*bar\\nbaz\",
+where `*' indicates point."
+  ;; Are we already at the end a part of a long line?
+  (unless (get-char-property (point) 'eat--t-wrap-line)
+    ;; Find the next end of a part of a long line.
+    (goto-char (next-single-char-property-change
+                (point) 'eat--t-wrap-line nil limit)))
+  ;; Remove the newline.
+  (when (< (point) (or limit (point-max)))
+    (1value (cl-assert (1value (= (1value (char-after)) ?\n))))
+    (delete-char 1)))
+
+(defun eat--t-break-long-line (threshold)
+  "Break a line longer than THRESHOLD once.
+
+For example: when THRESHOLD is 3, \"*foobarbaz\" is converted to
+\"foo\\n*barbaz\", where `*' indicates point."
+  (let ((loop t))
+    ;; Find a too long line.
+    (while (and loop (< (point) (point-max)))
+      ;; Go to the threshold column.
+      (eat--t-goto-col threshold)
+      ;; Are we at the end of line?
+      (if (eq (char-after) ?\n)
+          ;; We are already at the end of line, so move to the next
+          ;; line and start from the beginning.
+          (forward-char)
+        ;; The next character is not a newline, so we must be at a
+        ;; long, or we are the end of the accessible part of the
+        ;; buffer.  Whatever the case, we break the loop, and if it is
+        ;; a long line, we break the line.
+        (setq loop nil)
+        (unless (= (point) (point-max))
+          (insert-before-markers
+           (propertize "\n" 'eat--t-wrap-line t)))))))
+
+
+;;;; Emulator.
+
+(cl-defstruct (eat--t-cur
+               (:constructor eat--t-make-cur)
+               (:copier eat--t-copy-cur))
+  "Structure describing cursor position."
+  (position nil :documentation "Position of cursor.")
+  (y 1 :documentation "Y coordinate of cursor.")
+  (x 1 :documentation "X coordinate of cursor."))
+
+(cl-defstruct (eat--t-disp
+               (:constructor eat--t-make-disp)
+               (:copier eat--t-copy-disp))
+  "Structure describing the display."
+  (begin nil :documentation "Beginning of visible display.")
+  (width 80 :documentation "Width of display.")
+  (height 24 :documentation "Height of display.")
+  (cursor nil :documentation "Cursor.")
+  (saved-cursor
+   (1value (eat--t-make-cur))
+   :documentation "Saved cursor.")
+  (old-begin
+   nil
+   :documentation
+   "Beginning of visible display during last Eat redisplay."))
+
+(cl-defstruct (eat--t-face
+               (:constructor eat--t-make-face)
+               (:copier eat--t-copy-face))
+  "Structure describing the display attributes to use."
+  (face nil :documentation "Face to use.")
+  (fg nil :documentation "Foreground color.")
+  (bg nil :documentation "Background color.")
+  (intensity nil :documentation "Intensity face, or nil.")
+  (italic nil :documentation "Non-nil means use italic face.")
+  (underline nil :documentation "Non-nil means underline text.")
+  (underline-color nil :documentation "Underline color.")
+  (crossed nil :documentation "Non-nil means strike-through text.")
+  (conceal nil :documentation "Non-nil means invisible text.")
+  (inverse nil :documentation "Non-nil means inverse colors.")
+  (blink nil :documentation "Blink face, or nil.")
+  (font 'eat-term-font-0 :documentation "Current font face."))
+
+(cl-defstruct (eat--t-term
+               (:constructor eat--t-make-term)
+               (:copier eat--t-copy-term))
+  "Structure describing a terminal."
+  (buffer nil :documentation "The buffer of terminal.")
+  (begin nil :documentation "Beginning of terminal.")
+  (end nil :documentation "End of terminal area.")
+  (title "" :documentation "The title of the terminal.")
+  (bell-fn
+   (1value #'ignore)
+   :documentation "Function to ring the bell.")
+  (input-fn
+   (1value #'ignore)
+   :documentation "Function to send input.")
+  (set-cursor-fn
+   (1value #'ignore)
+   :documentation "Function to set cursor.")
+  (manipulate-selection-fn
+   (1value #'ignore)
+   :documentation "Function to manipulate selection.")
+  (set-title-fn
+   (1value #'ignore)
+   :documentation "Function to set title.")
+  (grab-mouse-fn
+   (1value #'ignore)
+   :documentation "Function to grab mouse.")
+  (set-focus-ev-mode-fn
+   (1value #'ignore)
+   :documentation "Function to set focus event mode.")
+  (parser-state nil :documentation "State of parser.")
+  (scroll-begin 1 :documentation "First line of scroll region.")
+  (scroll-end 24 :documentation "Last line of scroll region.")
+  (display nil :documentation "The display.")
+  (main-display nil :documentation "Main display.
+
+Nil when not in alternative display mode.")
+  (face
+   (1value (eat--t-make-face))
+   :documentation "Display attributes.")
+  (auto-margin t :documentation "State of auto margin mode.")
+  (ins-mode nil :documentation "State of insert mode.")
+  (charset
+   (copy-tree '(g0 . ((g0 . us-ascii)
+                      (g1 . us-ascii)
+                      (g2 . us-ascii)
+                      (g3 . us-ascii))))
+   :documentation "Current character set.")
+  (cur-state :default :documentation "Current state of cursor.")
+  (cur-blinking-p nil :documentation "Is the cursor blinking?")
+  (saved-face
+   (1value (eat--t-make-face))
+   :documentation "Saved SGR attributes.")
+  (bracketed-yank nil :documentation "State of bracketed yank mode.")
+  (keypad-mode nil :documentation "State of keypad mode.")
+  (mouse-mode nil :documentation "Current mouse mode.")
+  (mouse-pressed nil :documentation "Pressed mouse buttons.")
+  (mouse-encoding nil :documentation "Current mouse event encoding.")
+  (focus-event-mode nil :documentation "Whether to send focus event.")
+  (cut-buffers
+   (1value (make-vector 10 nil))
+   :documentation "Cut buffers."))
+
+(defvar eat--t-term nil
+  "The current terminal.
+
+Don't `set' it, bind it to a value with `let'.")
+
+(defun eat--t-reset ()
+  "Reset terminal."
+  (let* ((disp (eat--t-term-display eat--t-term)))
+    ;; Reset most of the things to their respective default values.
+    (setf (eat--t-term-parser-state eat--t-term) nil)
+    (setf (eat--t-disp-begin disp) (point-min-marker))
+    (setf (eat--t-disp-old-begin disp) (point-min-marker))
+    (setf (eat--t-disp-cursor disp)
+          (eat--t-make-cur :position (point-min-marker)))
+    (setf (eat--t-disp-saved-cursor disp) (eat--t-make-cur))
+    (setf (eat--t-term-scroll-begin eat--t-term) 1)
+    (setf (eat--t-term-scroll-end eat--t-term)
+          (eat--t-disp-height disp))
+    (setf (eat--t-term-main-display eat--t-term) nil)
+    (setf (eat--t-term-face eat--t-term) (eat--t-make-face))
+    (setf (eat--t-term-auto-margin eat--t-term) t)
+    (setf (eat--t-term-ins-mode eat--t-term) nil)
+    (setf (eat--t-term-charset eat--t-term)
+          '(g0 (g0 . us-ascii)
+               (g1 . dec-line-drawing)
+               (g2 . dec-line-drawing)
+               (g3 . dec-line-drawing)))
+    (setf (eat--t-term-saved-face eat--t-term) (eat--t-make-face))
+    (setf (eat--t-term-bracketed-yank eat--t-term) nil)
+    (setf (eat--t-term-cur-state eat--t-term) :default)
+    (setf (eat--t-term-cur-blinking-p eat--t-term) nil)
+    (setf (eat--t-term-title eat--t-term) "")
+    (setf (eat--t-term-keypad-mode eat--t-term) nil)
+    (setf (eat--t-term-mouse-mode eat--t-term) nil)
+    (setf (eat--t-term-mouse-encoding eat--t-term) nil)
+    (setf (eat--t-term-focus-event-mode eat--t-term) nil)
+    ;; Clear everything.
+    (delete-region (point-min) (point-max))
+    ;; Inform the UI about our new state.
+    (funcall (eat--t-term-grab-mouse-fn eat--t-term) eat--t-term nil)
+    (funcall (eat--t-term-set-focus-ev-mode-fn eat--t-term)
+             eat--t-term nil)
+    (funcall (eat--t-term-set-title-fn eat--t-term) eat--t-term "")
+    (funcall (eat--t-term-set-cursor-fn eat--t-term) eat--t-term
+             :default)))
+
+(defun eat--t-cur-right (&optional n)
+  "Move cursor N columns right.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is less than 1, set N to 1.  If N is more than the
+         ;; number of available columns on the right side, set N to
+         ;; the maximum possible value.
+         (n (min (- (eat--t-disp-width disp) (eat--t-cur-x cursor))
+                 (max (or n 1) 1))))
+    ;; N is non-zero in most cases, except at the edge of display.
+    (unless (zerop n)
+      ;; Move to the Nth next column, use spaces to reach that column
+      ;; if needed.
+      (eat--t-repeated-insert ?\  (- n (eat--t-col-motion n)))
+      (cl-incf (eat--t-cur-x cursor) n))))
+
+(defun eat--t-cur-left (&optional n)
+  "Move cursor N columns left.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is less than 1, set N to 1.  If N is more than the
+         ;; number of available columns on the left side, set N to the
+         ;; maximum possible value.
+         (n (min (1- (eat--t-cur-x cursor)) (max (or n 1) 1))))
+    ;; N is non-zero in most cases, except at the edge of display.
+    (unless (zerop n)
+      ;; Move to the Nth previous column.
+      (cl-assert (1value (>= (eat--t-current-col) n)))
+      (backward-char n)
+      (cl-decf (eat--t-cur-x cursor) n))))
+
+(defun eat--t-cur-horizontal-abs (&optional n)
+  "Move cursor to Nth column on current line.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is out of range, bring it within the bounds of range.
+         (n (min (max (or n 1) 1) (eat--t-disp-width disp))))
+    ;; Depending on the current position of cursor, move right or
+    ;; left.
+    (cond ((< (eat--t-cur-x cursor) n)
+           (eat--t-cur-right (- n (eat--t-cur-x cursor))))
+          ((< n (eat--t-cur-x cursor))
+           (eat--t-cur-left (- (eat--t-cur-x cursor) n))))))
+
+(defun eat--t-beg-of-next-line (n)
+  "Move to beginning of Nth next line."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is less than 1, set N to 1.  If N is more than the
+         ;; number of available lines below, set N to the maximum
+         ;; possible value.
+         (n (min (- (eat--t-disp-height disp) (eat--t-cur-y cursor))
+                 (max (or n 1) 1))))
+    ;; N is non-zero in most cases, except at the edge of display.
+    ;; Whatever the case, we move to the beginning of line.
+    (if (zerop n)
+        (1value (eat--t-goto-bol))
+      ;; Move to the Nth next line, use newlines to reach that line if
+      ;; needed.
+      (eat--t-repeated-insert ?\n (- n (eat--t-goto-bol n)))
+      (cl-incf (eat--t-cur-y cursor) n))
+    (1value (setf (eat--t-cur-x cursor) 1))))
+
+(defun eat--t-beg-of-prev-line (n)
+  "Move to beginning of Nth previous line."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is less than 1, set N to 1.  If N is more than the
+         ;; number of available lines above, set N to the maximum
+         ;; possible value.
+         (n (min (1- (eat--t-cur-y cursor)) (max (or n 1) 1))))
+    ;; Move to the beginning Nth previous line.  Even if there are no
+    ;; line above, move to the beginning of the line.
+    (eat--t-goto-bol (- n))
+    (cl-decf (eat--t-cur-y cursor) n)
+    (1value (setf (eat--t-cur-x cursor) 1))))
+
+(defun eat--t-cur-down (&optional n)
+  "Move cursor N lines down.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (x (eat--t-cur-x cursor)))
+    ;; Move to the beginning of target line.
+    (eat--t-beg-of-next-line n)
+    ;; If the cursor wasn't at column one, move the cursor to the
+    ;; cursor to that column.
+    (unless (= x 1)
+      (eat--t-cur-right (1- x)))))
+
+(defun eat--t-cur-up (&optional n)
+  "Move cursor N lines up.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (x (eat--t-cur-x cursor)))
+    ;; Move to the beginning of target line.
+    (eat--t-beg-of-prev-line n)
+    ;; If the cursor wasn't at column one, move the cursor to the
+    ;; cursor to that column.
+    (unless (= x 1)
+      (eat--t-cur-right (1- x)))))
+
+(defun eat--t-cur-vertical-abs (&optional n)
+  "Move cursor to Nth line on display.
+
+N default to 1.  If N is out of range, place cursor at the edge of
+display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; If N is out of range, bring it within the bounds of range.
+         (n (min (max (or n 1) 1) (eat--t-disp-height disp))))
+    ;; Depending on the current position of cursor, move downward or
+    ;; upward.
+    (cond ((< (eat--t-cur-y cursor) n)
+           (eat--t-cur-down (- n (eat--t-cur-y cursor))))
+          ((< n (eat--t-cur-y cursor))
+           (eat--t-cur-up (- (eat--t-cur-y cursor) n))))))
+
+(defun eat--t-scroll-up (&optional n as-side-effect)
+  "Scroll up N lines, preserving cursor position.
+
+N default to 1.  By default, don't change current line and current
+column, but if AS-SIDE-EFFECT is given and non-nil, assume that
+scrolling is triggered as a side effect of some other control function
+and don't move the point relative to the text and change current line
+accordingly."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-begin (eat--t-term-scroll-begin eat--t-term))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; N shouldn't be more more than the number of lines in
+         ;; scroll region.
+         (n (min (max (or n 1) 0) (1+ (- scroll-end scroll-begin)))))
+    ;; Make sure that N is positive.
+    (unless (zerop n)
+      ;; Try to not point relative to the text.
+      (save-excursion
+        (goto-char (eat--t-disp-begin disp))
+        ;; Move to the beginning of scroll region.
+        (eat--t-goto-bol (1- scroll-begin))
+        ;; If the first line on display isn't in scroll region or
+        ;; if this is the alternative display, delete text.
+        (if (or (eat--t-term-main-display eat--t-term)
+                (> scroll-begin 1))
+            (delete-region (point) (car (eat--t-bol n)))
+          ;; Otherwise, send the text to the scrollback area by
+          ;; advancing the display beginning marker.
+          (eat--t-goto-bol n)
+          ;; Make sure we're at the beginning of a line, because we
+          ;; might be at `point-max'.
+          (unless (or (= (point) (point-min))
+                      (= (char-before) ?\n))
+            (insert ?\n))
+          (set-marker (eat--t-disp-begin disp) (point)))
+        ;; Is the last line on display in scroll region?
+        (when (< scroll-begin (eat--t-disp-width disp))
+          ;; Go to the end of scroll region (before deleting or moving
+          ;; texts).
+          (eat--t-goto-bol (- (1+ (- scroll-end scroll-begin)) n))
+          ;; If there is anything after the scroll region, insert
+          ;; newlines to keep that text unmoved.
+          (when (< (point) (point-max))
+            (eat--t-repeated-insert ?\n n))))
+      ;; Recalculate point if needed.
+      (let ((recalc-point
+             (<= scroll-begin (eat--t-cur-y cursor) scroll-end)))
+        ;; If recalc-point is non-nil, and AS-SIDE-EFFECT is non-nil,
+        ;; update cursor position so that it is unmoved relative to
+        ;; surrounding text and reconsider point recalculation.
+        (when (and recalc-point as-side-effect)
+          (setq recalc-point (< (- (eat--t-cur-y cursor) n)
+                                scroll-begin))
+          (setf (eat--t-cur-y cursor)
+                (max (- (eat--t-cur-y cursor) n) scroll-begin)))
+        (when recalc-point
+          ;; Recalculate point.
+          (let ((y (eat--t-cur-y cursor))
+                (x (eat--t-cur-x cursor)))
+            (eat--t-goto 1 1)
+            (eat--t-goto y x)))))))
+
+(defun eat--t-scroll-down (&optional n)
+  "Scroll down N lines, preserving cursor position.
+
+N default to 1."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-begin (eat--t-term-scroll-begin eat--t-term))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; N shouldn't be more more than the number of lines in
+         ;; scroll region.
+         (n (min (max (or n 1) 0) (1+ (- scroll-end scroll-begin)))))
+    ;; Make sure that N is positive.
+    (unless (zerop n)
+      ;; Move to the beginning of scroll region.
+      (goto-char (eat--t-disp-begin disp))
+      (eat--t-goto-bol (1- scroll-begin))
+      ;; Insert newlines to push text downwards.
+      (eat--t-repeated-insert ?\n n)
+      ;; Go to the end scroll region (after inserting newlines).
+      (eat--t-goto-eol (- (1+ (- scroll-end scroll-begin)) (1+ n)))
+      ;; Delete the text that was pushed out of scroll region.
+      (when (< (point) (point-max))
+        (delete-region (point) (car (eat--t-eol n))))
+      ;; The cursor mustn't move, so we have to recalculate point.
+      (let ((y (eat--t-cur-y cursor))
+            (x (eat--t-cur-x cursor)))
+        (eat--t-goto 1 1)
+        (eat--t-goto y x)))))
+
+(defun eat--t-goto (&optional y x)
+  "Go to Xth column of Yth line of display.
+
+Y and X default to 1.  Y and X are one-based.  If Y and/or X are out
+of range, place cursor at the edge of display."
+  ;; Important special case: if Y and X are both one, move to the
+  ;; display beginning.
+  (if (and (or (not y) (eql y 1))
+           (or (not x) (eql x 1)))
+      (let* ((disp (eat--t-term-display eat--t-term))
+             (cursor (eat--t-disp-cursor disp)))
+        (goto-char (eat--t-disp-begin disp))
+        (1value (setf (eat--t-cur-y cursor) 1))
+        (1value (setf (eat--t-cur-x cursor) 1)))
+    ;; Move to column one, go to Yth line and move to Xth column.
+    ;; REVIEW: We move relative to cursor position, which faster for
+    ;; positions near the point (usually the case), but slower for
+    ;; positions far away from the point.  There are only two cursor
+    ;; positions whose exact position is known beforehand, the cursor
+    ;; (whose position is (point)) and (1, 1) (the display beginning).
+    ;; There are almost always some points which are at more distance
+    ;; from current position than from the display beginning (the only
+    ;; exception is when the cursor is at the display beginning).  So
+    ;; first moving to the display beginning and then moving to those
+    ;; point will be faster than moving from cursor (except a small
+    ;; (perhaps negligible) overhead of `goto-char').  What we don't
+    ;; have is a formula the calculate the distance between two
+    ;; positions.
+    (eat--t-cur-horizontal-abs 1)
+    (eat--t-cur-vertical-abs y)
+    (eat--t-cur-horizontal-abs x)))
+
+(defun eat--t-enable-auto-margin ()
+  "Enable automatic margin."
+  ;; Set the automatic margin flag to t, the rest of code will take
+  ;; care of the effects.
+  (1value (setf (eat--t-term-auto-margin eat--t-term) t)))
+
+(defun eat--t-disable-auto-margin ()
+  "Disable automatic margin."
+  ;; Set the automatic margin flag to nil, the rest of code will take
+  ;; care of the effects.
+  (1value (setf (eat--t-term-auto-margin eat--t-term) nil)))
+
+(defun eat--t-set-charset (slot charset)
+  "SLOT's character set to CHARSET."
+  (setf (alist-get slot (cdr (eat--t-term-charset eat--t-term)))
+        charset))
+
+(defun eat--t-change-charset (charset)
+  "Change character set to CHARSET.
+
+CHARSET should be one of `g0', `g1', `g2' and `g3'."
+  (setf (car (eat--t-term-charset eat--t-term)) charset))
+
+(defun eat--t-write (str)
+  "Write STR on display."
+  (let* ((str
+          ;; Convert STR to Unicode according to the current character
+          ;; set.
+          (pcase (alist-get (car (eat--t-term-charset eat--t-term))
+                            (cdr (eat--t-term-charset eat--t-term)))
+            ;; For `us-ascii', the default, no conversion is
+            ;; necessary.
+            ('us-ascii
+             str)
+            ;; `dec-line-drawing' contains various characters useful
+            ;; for drawing line diagram, so it is a must.  This is
+            ;; also possible with `us-ascii', thanks to Unicode, but
+            ;; the character set `dec-line-drawing' is usually less
+            ;; expensive in terms of bytes needed to transfer than
+            ;; `us-ascii'.
+            ('dec-line-drawing
+             (let ((s (copy-sequence str)))
+               (dotimes (i (length s))
+                 (let ((replacement (alist-get (aref s i)
+                                               '((?+ . ?→)
+                                                 (?, . ?←)
+                                                 (?- . ?↑)
+                                                 (?. . ?↓)
+                                                 (?0 . ?█)
+                                                 (?\` . ?�)
+                                                 (?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 . ?≥)
+                                                 (?{ . ?π)
+                                                 (?| . ?≠)
+                                                 (?} . ?£)
+                                                 (?~ . ?•)))))
+                   (when replacement
+                     (aset s i replacement))))
+               s))
+            (_
+             str)))
+         ;; Add `face' property.
+         (str (propertize str 'face
+                          (eat--t-face-face
+                           (eat--t-term-face eat--t-term)))))
+    ;; TODO: Comment.
+    ;; REVIEW: This probably needs to be updated.
+    (let* ((disp (eat--t-term-display eat--t-term))
+           (cursor (eat--t-disp-cursor disp))
+           (scroll-end (eat--t-term-scroll-end eat--t-term)))
+      (while (not (string-empty-p str))
+        (let ((ins-count (min (- (eat--t-disp-width disp)
+                                 (1- (eat--t-cur-x cursor)))
+                              (length str))))
+          (insert (substring str 0 ins-count))
+          (setq str (substring str ins-count))
+          (cl-incf (eat--t-cur-x cursor) ins-count)
+          (if (eat--t-term-ins-mode eat--t-term)
+              (delete-region
+               (save-excursion
+                 (eat--t-col-motion (- (eat--t-disp-width disp)
+                                       (1- (eat--t-cur-x cursor))))
+                 (point))
+               (car (eat--t-eol)))
+            (delete-region (point) (min (+ ins-count (point))
+                                        (car (eat--t-eol)))))
+          (when (> (eat--t-cur-x cursor) (eat--t-disp-width disp))
+            (if (not (eat--t-term-auto-margin eat--t-term))
+                (eat--t-cur-left 1)
+              (unless (string-empty-p str)
+                (when (= (eat--t-cur-y cursor) scroll-end)
+                  (eat--t-scroll-up 1 'as-side-effect))
+                (if (= (eat--t-cur-y cursor) scroll-end)
+                    (eat--t-carriage-return)
+                  (if (= (point) (point-max))
+                      (insert (propertize "\n" 'eat--t-wrap-line t))
+                    (put-text-property (point) (1+ (point))
+                                       'eat--t-wrap-line t)
+                    (forward-char))
+                  (1value (setf (eat--t-cur-x cursor) 1))
+                  (cl-incf (eat--t-cur-y cursor)))))))))))
+
+(defun eat--t-horizontal-tab (&optional n)
+  "Go to the Nth next tabulation stop.
+
+N default to 1."
+  (let* ((n (max (or n 1) 1))           ; N must be positive.
+         (disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp)))
+    ;; Do some math calculate the distance of the Nth next tabulation
+    ;; stop from cursor, and go there.
+    (eat--t-cur-right (+ (- 8 (mod (1- (eat--t-cur-x cursor)) 8))
+                         (* (1- n) 8)))))
+
+(defun eat--t-horizontal-backtab (&optional n)
+  "Go to the Nth previous tabulation stop.
+
+N default to 1."
+  (let* ((n (max (or n 1) 1))           ; N must be positive.
+         (disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp)))
+    ;; Do some math calculate the distance of the Nth next tabulation
+    ;; stop from cursor, and go there.
+    (eat--t-cur-left (+ (1+ (mod (- (eat--t-cur-x cursor) 2) 8))
+                        (* (1- n) 8)))))
+
+(defun eat--t-index ()
+  "Go to the next line preserving column, scrolling if necessary."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; Are we inside scroll region?
+         (in-scroll-region (<= (eat--t-cur-y cursor) scroll-end)))
+    ;; If this is the last line (of the scroll region or the display),
+    ;; scroll up, otherwise move cursor downward.
+    (if (= (if in-scroll-region scroll-end (eat--t-disp-height disp))
+           (eat--t-cur-y cursor))
+        (eat--t-scroll-up 1)
+      (eat--t-cur-down 1))))
+
+(defun eat--t-carriage-return ()
+  "Go to column one."
+  (eat--t-cur-horizontal-abs 1))
+
+(defun eat--t-line-feed ()
+  "Go to the first column of the next line, scrolling if necessary."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; Are we inside scroll region?
+         (in-scroll-region (<= (eat--t-cur-y cursor) scroll-end)))
+    ;; If we are at the very end of the terminal, we might have some
+    ;; optimizations.
+    (if (= (point) (point-max))
+        ;; If the cursor is above the last line of the scroll region
+        ;; (or the display, if we are outside the scroll region), we
+        ;; can simply insert a newline and update the cursor position.
+        (if (/= (if in-scroll-region
+                    scroll-end
+                  (eat--t-disp-height disp))
+                (eat--t-cur-y cursor))
+            (progn
+              (insert ?\n)
+              (setf (eat--t-cur-x cursor) 1)
+              (cl-incf (eat--t-cur-y cursor)))
+          ;; This is the last line.  We need to scroll up.
+          (eat--t-scroll-up 1 'as-side-effect)
+          ;; If we're still at the last line (only happens when the
+          ;; display has only a single line), go to column one of it.
+          (if (= (if in-scroll-region
+                     scroll-end
+                   (eat--t-disp-height disp))
+                 (eat--t-cur-y cursor))
+              (eat--t-carriage-return)
+            ;; If we are somehow moved from the end of terminal,
+            ;; `eat--t-beg-of-next-line' is the best option.
+            (if (/= (point) (point-max))
+                (eat--t-beg-of-next-line 1)
+              ;; We are still at the end!  We can can simply insert a
+              ;; newline and update the cursor position.
+              (insert ?\n)
+              (setf (eat--t-cur-x cursor) 1)
+              (cl-incf (eat--t-cur-y cursor)))))
+      ;; We are not at the end of terminal.  But we still have a last
+      ;; chance.  `eat--t-beg-of-next-line' is usually faster than
+      ;; `eat--t-carriage-return' followed by `eat--t-index', so if
+      ;; there is at least a single line (in the scroll region, if the
+      ;; cursor in the scroll region, otherwise in the display)
+      ;; underneath the cursor, we can use `eat--t-beg-of-next-line'.
+      (if (/= (if in-scroll-region
+                  scroll-end
+                (eat--t-disp-height disp))
+              (eat--t-cur-y cursor))
+          (eat--t-beg-of-next-line 1)
+        ;; We don't have any other option, so we must use the most
+        ;; time-expensive option.
+        (eat--t-carriage-return)
+        (eat--t-index)))))
+
+(defun eat--t-reverse-index ()
+  "Go to the previous line preserving column, scrolling if needed."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-begin (eat--t-term-scroll-begin eat--t-term))
+         ;; Are we in the scroll region?
+         (in-scroll-region (<= scroll-begin (eat--t-cur-y cursor))))
+    ;; If this is the first line (of the scroll region or the
+    ;; display), scroll down, otherwise move cursor upward.
+    (if (= (if in-scroll-region scroll-begin 1)
+           (eat--t-cur-y cursor))
+        (eat--t-scroll-down 1)
+      (eat--t-cur-up 1))))
+
+(defun eat--t-bell ()
+  "Ring the bell."
+  ;; Call the UI's bell handler.
+  (funcall (eat--t-term-bell-fn eat--t-term) eat--t-term))
+
+(defun eat--t-form-feed ()
+  "Insert a vertical tab."
+  ;; Form feed is same as `eat--t-index'.
+  (eat--t-index))
+
+(defun eat--t-save-cur ()
+  "Save current cursor position."
+  (let ((disp (eat--t-term-display eat--t-term))
+        (saved-face (eat--t-copy-face
+                     (eat--t-term-face eat--t-term))))
+    ;; Save cursor position.
+    (setf (eat--t-disp-saved-cursor disp)
+          (eat--t-copy-cur (eat--t-disp-cursor disp)))
+    ;; Save SGR attributes.
+    (setf (eat--t-term-saved-face eat--t-term) saved-face)
+    ;; We use side-effects, so make sure the saved face doesn't share
+    ;; structure with the current face.
+    (setf (eat--t-face-face saved-face)
+          (copy-tree (eat--t-face-face saved-face)))
+    (setf (eat--t-face-underline-color saved-face)
+          (copy-tree (eat--t-face-underline-color saved-face)))))
+
+(defun eat--t-restore-cur ()
+  "Restore previously save cursor position."
+  (let ((saved (eat--t-disp-saved-cursor
+                (eat--t-term-display eat--t-term))))
+    ;; Restore cursor position.
+    (eat--t-goto (eat--t-cur-y saved) (eat--t-cur-x saved))
+    ;; Restore SGR attributes.
+    (setf (eat--t-term-face eat--t-term)
+          (copy-tree (eat--t-term-saved-face eat--t-term)))
+    (setf (eat--t-face-underline-color (eat--t-term-face eat--t-term))
+          (copy-tree (eat--t-face-underline-color
+                      (eat--t-term-face eat--t-term))))))
+
+(defun eat--t-erase-in-line (&optional n)
+  "Erase part of current line, but don't move cursor.
+
+N defaults to 0.  When N is 0, erase cursor to end of line.  When N is
+1, erase beginning of line to cursor.  When N is 2, erase whole line."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp)))
+    (pcase n
+      ((or 0 'nil (pred (< 2)))
+       ;; Delete cursor position (inclusive) to end of line.
+       (delete-region (point) (car (eat--t-eol)))
+       ;; If the SGR background attribute is set, we need to fill the
+       ;; erased area with that background.
+       (when (eat--t-face-bg face)
+         (save-excursion
+           (eat--t-repeated-insert
+            ?\  (1+ (- (eat--t-disp-width disp)
+                       (eat--t-cur-x cursor)))
+            (and (eat--t-face-bg face)
+                 (eat--t-face-face face))))))
+      (1
+       ;; Delete beginning of line to cursor position (inclusive).
+       (delete-region (car (eat--t-bol))
+                      (if (or (= (point) (point-max))
+                              (= (char-after) ?\n))
+                          (point)
+                        (1+ (point))))
+       ;; Fill the region with spaces, use SGR background attribute
+       ;; if set.
+       (eat--t-repeated-insert ?\  (eat--t-cur-x cursor)
+                               (and (eat--t-face-bg face)
+                                    (eat--t-face-face face)))
+       ;; We erased the character at the cursor position, so after
+       ;; fill with spaces we are still off by one column; so move a
+       ;; column backward.
+       (backward-char))
+      (2
+       ;; Delete whole line.
+       (delete-region (car (eat--t-bol)) (car (eat--t-eol)))
+       ;; Fill the region before cursor position with spaces, use SGR
+       ;; background attribute if set.
+       (eat--t-repeated-insert ?\  (1- (eat--t-cur-x cursor))
+                               (and (eat--t-face-bg face)
+                                    (eat--t-face-face face)))
+       ;; If the SGR background attribute is set, we need to fill the
+       ;; erased area including and after cursor position with that
+       ;; background.
+       (when (eat--t-face-bg face)
+         (save-excursion
+           (eat--t-repeated-insert
+            ?\  (1+ (- (eat--t-disp-width disp)
+                       (eat--t-cur-x cursor)))
+            (and (eat--t-face-bg face)
+                 (eat--t-face-face face)))))))))
+
+(defun eat--t-erase-in-disp (&optional n)
+  "Erase part of display.
+
+N defaults to 0.  When N is 0, erase cursor to end of display.  When N
+is 1, erase beginning of display to cursor.  In both on the previous
+cases, don't move cursor.  When N is 2, erase display and reset cursor
+to (1, 1).  When N is 3, also erase the scrollback."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp)))
+    (pcase n
+      ((or 0 'nil (pred (< 3)))
+       ;; Delete from cursor position (inclusive) to end of terminal.
+       (delete-region (point) (point-max))
+       ;; If the SGR background attribute is set, we need to fill the
+       ;; erased area with that background.
+       (when (eat--t-face-bg face)
+         ;; `save-excursion' probably uses marker to save point, which
+         ;; doesn't work in this case.  So we the store the point as a
+         ;; integer.
+         (let ((pos (point)))
+           ;; Fill current line.
+           (eat--t-repeated-insert ?\  (1+ (- (eat--t-disp-width disp)
+                                              (eat--t-cur-x cursor)))
+                                   (eat--t-face-face face))
+           ;; Fill the following lines.
+           (dotimes (_ (- (eat--t-disp-height disp)
+                          (eat--t-cur-y cursor)))
+             (insert ?\n)
+             (eat--t-repeated-insert ?\  (eat--t-disp-width disp)
+                                     (eat--t-face-face face)))
+           ;; Restore position.
+           (goto-char pos))))
+      (1
+       (let* ((y (eat--t-cur-y cursor))
+              (x (eat--t-cur-x cursor))
+              ;; Should we erase including the cursor position?
+              (incl-point (/= (point) (point-max))))
+         ;; Delete the region to be erased.
+         (delete-region (eat--t-disp-begin disp)
+                        (if incl-point (1+ (point)) (point)))
+         ;; If the SGR background attribute isn't set, insert
+         ;; newlines, otherwise fill the erased area above the current
+         ;; line with background color.
+         (if (not (eat--t-face-bg face))
+             (eat--t-repeated-insert ?\n (1- y))
+           (dotimes (_ (1- y))
+             (eat--t-repeated-insert ?\  (eat--t-disp-width disp)
+                                     (eat--t-face-face face))
+             (insert ?\n)))
+         ;; Fill the current line to keep the cursor unmoved.  Use
+         ;; background if the corresponding SGR attribute is set.
+         (eat--t-repeated-insert ?\  x (and (eat--t-face-bg face)
+                                            (eat--t-face-face face)))
+         ;; We are off by one column; so move a column backward.
+         (when incl-point
+           (backward-char))))
+      ((or 2 3)
+       ;; Move to the display beginning.
+       (eat--t-goto 1 1)
+       ;; Delete everything in the display, and if N is 3, also delete
+       ;; everything in the scrollback area.
+       (delete-region (if (= n 2) (point) (point-min))
+                      (point-max))
+       ;; If the SGR background attribute is set, fill the display
+       ;; with that background.
+       (when (eat--t-face-bg face)
+         ;; `save-excursion' probably uses marker to save point, which
+         ;; doesn't work in this case.  So we the store the point as a
+         ;; integer.
+         (let ((pos (point)))
+           (dotimes (i (eat--t-disp-height disp))
+             (unless (zerop i)
+               (insert ?\n))
+             (eat--t-repeated-insert ?\  (eat--t-disp-width disp)
+                                     (eat--t-face-face face)))
+           ;; Restore point.
+           (goto-char pos)))))))
+
+(defun eat--t-device-status-report ()
+  "Send the current Y and X coordinate to client."
+  ;; TODO: Is this really device status report function?
+  (let ((cursor (eat--t-disp-cursor
+                 (eat--t-term-display eat--t-term))))
+    (funcall (eat--t-term-input-fn eat--t-term) eat--t-term
+             (format "\e[%i;%iR" (eat--t-cur-y cursor)
+                     (eat--t-cur-x cursor)))))
+
+(defun eat--t-set-cursor-state (state)
+  "Set cursor state to STATE.
+
+STATE one of the `:default', `:invisible', `:very-visible'."
+  (unless (eq (eat--t-term-cur-state eat--t-term) state)
+    ;; Update state.
+    (setf (eat--t-term-cur-state eat--t-term) state)
+    ;; Inform the UI.
+    (funcall (eat--t-term-set-cursor-fn eat--t-term) eat--t-term
+             state)))
+
+(defun eat--t-default-cursor ()
+  "Set the cursor to its default state."
+  (eat--t-set-cursor-state
+   (if (eat--t-term-cur-blinking-p eat--t-term)
+       :very-visible
+     :default)))
+
+(defun eat--t-invisible-cursor ()
+  "Make the cursor invisible."
+  (eat--t-set-cursor-state :invisible))
+
+(defun eat--t-blinking-cursor ()
+  "Make the cursor blink."
+  (setf (eat--t-term-cur-blinking-p eat--t-term) t)
+  (when (eq (eat--t-term-cur-state eat--t-term) :default)
+    (eat--t-set-cursor-state :very-visible)))
+
+(defun eat--t-non-blinking-cursor ()
+  "Make the cursor not blink."
+  (setf (eat--t-term-cur-blinking-p eat--t-term) nil)
+  (when (eq (eat--t-term-cur-state eat--t-term) :very-visible)
+    (eat--t-set-cursor-state :default)))
+
+(defun eat--t-enable-bracketed-yank ()
+  "Enable bracketed yank mode."
+  (setf (eat--t-term-bracketed-yank eat--t-term) t))
+
+(defun eat--t-disable-bracketed-yank ()
+  "Disable bracketed yank mode."
+  (setf (eat--t-term-bracketed-yank eat--t-term) nil))
+
+(defun eat--t-enable-alt-disp ()
+  "Enable alternative display."
+  ;; Effective only when alternative display is enabled by user.
+  (when eat-enable-alternative-display
+    ;; Make sure we not already in the alternative display.
+    (unless (eat--t-term-main-display eat--t-term)
+      ;; Store the current display, including scrollback.
+      (let ((main-disp (eat--t-copy-disp
+                        (eat--t-term-display eat--t-term))))
+        (setf (eat--t-disp-begin main-disp)
+              (- (eat--t-disp-begin main-disp) (point-min)))
+        (setf (eat--t-disp-old-begin main-disp)
+              (- (eat--t-disp-old-begin main-disp) (point-min)))
+        (setf (eat--t-disp-cursor main-disp)
+              (eat--t-copy-cur (eat--t-disp-cursor main-disp)))
+        (setf (eat--t-disp-saved-cursor main-disp)
+              (eat--t-copy-cur (eat--t-disp-saved-cursor main-disp)))
+        (setf (eat--t-cur-position (eat--t-disp-cursor main-disp))
+              (- (point) (point-min)))
+        (setf (eat--t-term-main-display eat--t-term)
+              (cons main-disp (buffer-string)))
+        ;; Delete everything, and move to the beginning of terminal.
+        (delete-region (point-min) (point-max))
+        (eat--t-goto 1 1)))))
+
+(defun eat--t-disable-alt-disp (&optional dont-move-cursor)
+  "Disable alternative display.
+
+If DONT-MOVE-CURSOR is non-nil, don't move cursor from current
+position."
+  ;; Make sure we in the alternative display.
+  (when (eat--t-term-main-display eat--t-term)
+    (let* ((main-disp (eat--t-term-main-display eat--t-term))
+           (old-y (eat--t-cur-y
+                   (eat--t-disp-cursor
+                    (eat--t-term-display eat--t-term))))
+           (old-x (eat--t-cur-x
+                   (eat--t-disp-cursor
+                    (eat--t-term-display eat--t-term))))
+           (width (eat--t-disp-width
+                   (eat--t-term-display eat--t-term)))
+           (height (eat--t-disp-height
+                    (eat--t-term-display eat--t-term))))
+      ;; Delete everything.
+      (delete-region (point-min) (point-max))
+      ;; Restore the main display.
+      (insert (cdr main-disp))
+      (setf (eat--t-disp-begin (car main-disp))
+            (copy-marker (+ (point-min)
+                            (eat--t-disp-begin (car main-disp)))))
+      (setf (eat--t-disp-old-begin (car main-disp))
+            (copy-marker (+ (point-min)
+                            (eat--t-disp-old-begin (car main-disp)))))
+      (setf (eat--t-cur-position (eat--t-disp-cursor (car main-disp)))
+            (copy-marker (+ (point-min)
+                            (eat--t-cur-position
+                             (eat--t-disp-cursor (car main-disp))))))
+      (setf (eat--t-term-display eat--t-term) (car main-disp))
+      (setf (eat--t-term-main-display eat--t-term) nil)
+      (goto-char (eat--t-cur-position
+                  (eat--t-disp-cursor
+                   (eat--t-term-display eat--t-term))))
+      ;; Maybe the terminal was resized after enabling alternative
+      ;; display, so we have to resize again.
+      (eat--t-resize width height)
+      ;; Restore cursor position if DONT-MOVE-CURSOR is non-nil.
+      (when dont-move-cursor
+        (eat--t-goto old-y old-x)))))
+
+(defun eat--t-insert-char (n)
+  "Insert N empty (space) characters, preserving cursor."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; Make sure N is positive.  If N is more than the number of
+         ;; available columns available, set N to the maximum possible
+         ;; value.
+         (n (min (- (eat--t-disp-width disp)
+                    (1- (eat--t-cur-x cursor)))
+                 (max (or n 1) 1))))
+    ;; Return if N is zero.
+    (unless (zerop n)
+      (save-excursion
+        ;; Insert N spaces, with SGR background if that attribute is
+        ;; set.
+        (eat--t-repeated-insert ?\  n (and (eat--t-face-bg face)
+                                           (eat--t-face-face face)))
+        ;; Remove the characters that went beyond the edge of display.
+        (eat--t-col-motion (- (eat--t-disp-width disp)
+                              (+ (1- (eat--t-cur-x cursor)) n)))
+        (delete-region (point) (car (eat--t-eol)))))))
+
+(defun eat--t-delete-char (n)
+  "Delete N characters, preserving cursor."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; Make sure N is positive.  If N is more than the number of
+         ;; available columns available, set N to the maximum possible
+         ;; value.
+         (n (min (- (eat--t-disp-width disp)
+                    (1- (eat--t-cur-x cursor)))
+                 (max (or n 1) 1))))
+    ;; Return if N is zero.
+    (unless (zerop n)
+      (save-excursion
+        (let ((m (point)))
+          ;; Delete N character on current line.
+          (eat--t-col-motion n)
+          (delete-region m (point))
+          ;; If SGR background attribute is set, fill N characters at
+          ;; the right edge of display with that background.
+          (when (eat--t-face-bg face)
+            (save-excursion
+              (eat--t-goto-eol)
+              (let ((empty (1+ (- (eat--t-disp-width disp)
+                                  (eat--t-cur-x cursor)
+                                  (- (point) m)))))
+                ;; Reach the position from where to start filling.
+                ;; Use spaces if needed.
+                (when (> empty n)
+                  (eat--t-repeated-insert ?\  (- empty n)))
+                ;; Fill with background.
+                (eat--t-repeated-insert
+                 ?\  (min empty n) (eat--t-face-face face))))))))))
+
+(defun eat--t-erase-char (n)
+  "Make next N character cells empty, preserving cursor."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         ;; Make sure N is positive.  If N is more than the number of
+         ;; available columns available, set N to the maximum possible
+         ;; value.
+         (n (min (- (eat--t-disp-width disp)
+                    (1- (eat--t-cur-x cursor)))
+                 (max (or n 1) 1))))
+    ;; Return if N is zero.
+    (unless (zerop n)
+      (save-excursion
+        (let ((m (point)))
+          ;; Delete N character on current line.
+          (eat--t-col-motion n)
+          (delete-region m (point))
+          ;; Insert N spaces, with background if SGR background
+          ;; attribute is set.
+          (eat--t-repeated-insert
+           ?\  n (and (eat--t-face-bg face)
+                      (eat--t-face-face face))))))))
+
+(defun eat--t-insert-line (n)
+  "Insert N empty lines, preserving cursor."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (scroll-begin (eat--t-term-scroll-begin eat--t-term))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; N should be positive and shouldn't exceed the number of
+         ;; lines below cursor position and inside current scroll
+         ;; region.
+         (n (min (- (1+ (- scroll-end scroll-begin))
+                    (1- (eat--t-cur-y cursor)))
+                 (max (or n 1) 1))))
+    ;; Make sure we are in the scroll region and N is positive, return
+    ;; on failure.
+    (when (and (<= scroll-begin (eat--t-cur-y cursor) scroll-end)
+               (not (zerop n)))
+      (goto-char
+       (prog1
+           (progn
+             ;; This function doesn't move the cursor, but pushes all
+             ;; the line below and including current line.  So to keep
+             ;; the cursor unmoved, go to the beginning of line and
+             ;; insert enough spaces to not move the cursor.
+             (eat--t-goto-bol)
+             (eat--t-repeated-insert ?\  (1- (eat--t-cur-x cursor))
+                                     (and (eat--t-face-bg face)
+                                          (eat--t-face-face face)))
+             (point))
+         ;; Insert N lines.
+         (if (not (eat--t-face-bg face))
+             (eat--t-repeated-insert ?\n n)
+           ;; SGR background attribute set, so fill the inserted lines
+           ;; with background.
+           (dotimes (i n)
+             ;; Fill a line.
+             (eat--t-repeated-insert
+              ?\  (if (not (zerop i))
+                      (eat--t-disp-width disp)
+                    ;; The first inserted line is already filled
+                    ;; partially, so calculate the number columns left
+                    ;; to fill.
+                    (1+ (- (eat--t-disp-width disp)
+                           (eat--t-cur-x cursor))))
+              (eat--t-face-face face))
+             ;; New line.
+             (insert ?\n)))
+         ;; Delete the lines that were just pushed beyond the end of
+         ;; scroll region.
+         (eat--t-goto-eol (- (1+ (- scroll-end scroll-begin))
+                             (+ (- (eat--t-cur-y cursor)
+                                   (1- scroll-begin))
+                                n)))
+         (delete-region (point) (car (eat--t-eol n))))))))
+
+(defun eat--t-delete-line (n)
+  "Delete N lines, preserving cursor."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (face (eat--t-term-face eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (x (eat--t-cur-x cursor))
+         (scroll-begin (eat--t-term-scroll-begin eat--t-term))
+         (scroll-end (eat--t-term-scroll-end eat--t-term))
+         ;; N should be positive and shouldn't exceed the number of
+         ;; lines below cursor position and inside current scroll
+         ;; region.
+         (n (min (- (1+ (- scroll-end scroll-begin))
+                    (1- (eat--t-cur-y cursor)))
+                 (max (or n 1) 1))))
+    ;; Make sure we are in the scroll region and N is positive, return
+    ;; on failure.
+    (when (and (<= scroll-begin (eat--t-cur-y cursor) scroll-end)
+               (not (zerop n)))
+      ;; Delete N lines (including the current one).
+      (eat--t-goto-bol)
+      (save-excursion
+        (let ((m (point)))
+          (eat--t-goto-bol n)
+          (delete-region m (point))))
+      ;; Keep the lines beyond end of scroll region unmoved.
+      (when (or (< scroll-end (eat--t-disp-height disp))
+                (eat--t-face-bg face))
+        (let* ((pos (point))
+               (move (- (1+ (- scroll-end scroll-begin))
+                        (- (+ (eat--t-cur-y cursor) n)
+                           (1- scroll-begin))))
+               (moved (eat--t-goto-eol move)))
+          (when (or (/= (point) (point-max))
+                    (eat--t-face-bg face))
+            ;; Move to the end of scroll region.
+            (eat--t-repeated-insert ?\n (- move moved))
+            ;; Insert enough new lines, fill them when SGR background
+            ;; attribute is set.
+            (if (not (eat--t-face-bg face))
+                (eat--t-repeated-insert ?\n n)
+              (dotimes (_ n)
+                (insert ?\n)
+                (eat--t-repeated-insert ?\  (eat--t-disp-width disp)
+                                        (eat--t-face-face face)))))
+          (goto-char pos)))
+      ;; Go to column where cursor is to preserve cursor position, use
+      ;; spaces if needed to reach the position.
+      (eat--t-repeated-insert
+       ?\  (- (1- x) (eat--t-col-motion (1- x)))))))
+
+(defun eat--t-repeat-last-char (&optional n)
+  "Repeat last character N times."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         ;; N must be at least one.
+         (n (max (or n 1) 1))
+         (char
+          ;; Get the character before cursor.
+          (when (< (eat--t-disp-begin disp) (point))
+            (if (get-text-property (1- (point)) 'eat--t-wrap-line)
+                ;; The character before cursor is a newline to break
+                ;; a long line, so use the character before that.
+                (when (< (eat--t-disp-begin disp) (1- (point)))
+                  (char-before (1- (point))))
+              (char-before)))))
+    ;; Insert `char' N times.  Make sure `char' is a non-nil and not
+    ;; a newline.
+    (when (and char (/= char ?\n))
+      (eat--t-write (make-string n char)))))
+
+(defun eat--t-change-scroll-region (&optional top bottom)
+  "Change the scroll region from lines TOP to BOTTOM (inclusive).
+
+TOP defaults to 1 and BOTTOM defaults to the height of the display."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (top (or top 1))
+         (bottom (or bottom (eat--t-disp-height disp))))
+    ;; According to DEC's documentation (found somewhere on the
+    ;; internet, but can't remember where), TOP and BOTTOM must be
+    ;; within display, and BOTTOM must be below TOP.  Otherwise the
+    ;; control function is a nop.
+    (when (< 0 top bottom (1+ (eat--t-disp-height disp)))
+      (setf (eat--t-term-scroll-begin eat--t-term) top)
+      (setf (eat--t-term-scroll-end eat--t-term) bottom)
+      (eat--t-goto 1 1))))
+
+(defun eat--t-insert-mode ()
+  "Enable insert mode and disable replace mode."
+  (setf (eat--t-term-ins-mode eat--t-term) t))
+
+(defun eat--t-replace-mode ()
+  "Enable replace mode and disable insert mode."
+  (setf (eat--t-term-ins-mode eat--t-term) nil))
+
+(defun eat--t-set-sgr-params (params)
+  "Set SGR parameters PARAMS."
+  (let ((face (eat--t-term-face eat--t-term)))
+    ;; Set attributes.
+    (while params
+      (pcase (pop params)
+        (`(,(or 0 'nil))
+         (1value (setf (eat--t-face-fg face) nil))
+         (1value (setf (eat--t-face-bg face) nil))
+         (1value (setf (eat--t-face-intensity face) nil))
+         (1value (setf (eat--t-face-italic face) nil))
+         (1value (setf (eat--t-face-underline face) nil))
+         (1value (setf (eat--t-face-underline-color face) nil))
+         (1value (setf (eat--t-face-crossed face) nil))
+         (1value (setf (eat--t-face-conceal face) nil))
+         (1value (setf (eat--t-face-inverse face) nil))
+         (1value (setf (eat--t-face-blink face) nil))
+         (1value (setf (eat--t-face-font face) 'eat-term-font-0)))
+        ('(1)
+         (1value (setf (eat--t-face-intensity face) 'eat-term-bold)))
+        ('(2)
+         (1value (setf (eat--t-face-intensity face) 'eat-term-faint)))
+        ('(3)
+         (1value (setf (eat--t-face-italic face) 'eat-term-italic)))
+        ('(4)
+         (1value (setf (eat--t-face-underline face) 'line)))
+        ('(4 0)
+         (1value (setf (eat--t-face-underline face) nil)))
+        ('(4 1)
+         (1value (setf (eat--t-face-underline face) 'line)))
+        ('(4 2)
+         (1value (setf (eat--t-face-underline face) 'line)))
+        ('(4 3)
+         (1value (setf (eat--t-face-underline face) 'wave)))
+        ('(4 4)
+         (1value (setf (eat--t-face-underline face) 'wave)))
+        ('(4 5)
+         (1value (setf (eat--t-face-underline face) 'wave)))
+        ('(5)
+         (1value (setf (eat--t-face-blink face) 'eat-term-slow-blink)))
+        ('(6)
+         (setf (eat--t-face-blink face) 'eat-term-fast-blink))
+        ('(7)
+         (1value (1value (setf (eat--t-face-inverse face) t))))
+        ('(8)
+         (1value (setf (eat--t-face-conceal face) t)))
+        ('(9)
+         (1value (setf (eat--t-face-crossed face) t)))
+        (`(,(and (pred (lambda (font) (<= 10 font 19)))
+                 font))
+         (setf (eat--t-face-font face)
+               (intern (format "eat-term-font-%i" (- font 10)))))
+        ('(21)
+         (1value (setf (eat--t-face-underline face) 'line)))
+        ('(22)
+         (1value (setf (eat--t-face-intensity face) nil)))
+        ('(23)
+         (1value (setf (eat--t-face-italic face) nil)))
+        ('(24)
+         (1value (setf (eat--t-face-underline face) nil)))
+        ('(25)
+         (1value (setf (eat--t-face-blink face) nil)))
+        ('(27)
+         (1value (setf (eat--t-face-inverse face) nil)))
+        ('(28)
+         (1value (setf (eat--t-face-conceal face) nil)))
+        ('(29)
+         (1value (setf (eat--t-face-crossed face) nil)))
+        (`(,(and (pred (lambda (color) (<= 30 color 37)))
+                 color))
+         (setf (eat--t-face-fg face)
+               (face-foreground
+                (intern (format "eat-term-color-%i" (- color 30)))
+                nil t)))
+        ('(38)
+         (pcase (pop params)
+           ('(2)
+            (setf (eat--t-face-fg face)
+                  (let ((r (car (pop params)))
+                        (g (car (pop params)))
+                        (b (car (pop params))))
+                    (when (and r (<= 0 r 255)
+                               g (<= 0 g 255)
+                               b (<= 0 b 255))
+                      (format "#%02x%02x%02x" r g b)))))
+           ('(5)
+            (let ((color (car (pop params))))
+              (setf (eat--t-face-fg face)
+                    (when (and color (<= 0 color 255))
+                      (face-foreground
+                       (intern (format "eat-term-color-%i" color))
+                       nil t)))))))
+        ('(39)
+         (1value (setf (eat--t-face-fg face) nil)))
+        (`(,(and (pred (lambda (color) (<= 40 color 47)))
+                 color))
+         (setf (eat--t-face-bg face)
+               (face-foreground
+                (intern (format "eat-term-color-%i" (- color 40)))
+                nil t)))
+        ('(48)
+         (setf (eat--t-face-bg face)
+               (pcase (pop params)
+                 ('(2)
+                  (let ((r (car (pop params)))
+                        (g (car (pop params)))
+                        (b (car (pop params))))
+                    (when (and r (<= 0 r 255)
+                               g (<= 0 g 255)
+                               b (<= 0 b 255))
+                      (format "#%02x%02x%02x" r g b))))
+                 ('(5)
+                  (let ((color (car (pop params))))
+                    (when (and color (<= 0 color 255))
+                      (face-foreground
+                       (intern (format "eat-term-color-%i" color))
+                       nil t)))))))
+        ('(49)
+         (1value (setf (eat--t-face-bg face) nil)))
+        ('(58)
+         (setf (eat--t-face-underline-color face)
+               (pcase (pop params)
+                 ('(2)
+                  (let ((r (car (pop params)))
+                        (g (car (pop params)))
+                        (b (car (pop params))))
+                    (when (and r (<= 0 r 255)
+                               g (<= 0 g 255)
+                               b (<= 0 b 255))
+                      (format "#%02x%02x%02x" r g b))))
+                 ('(5)
+                  (let ((color (car (pop params))))
+                    (when (and color (<= 0 color 255))
+                      (face-foreground
+                       (intern (format "eat-term-color-%i" color))
+                       nil t)))))))
+        ('(59)
+         (1value (setf (eat--t-face-underline-color face) nil)))
+        (`(,(and (pred (lambda (color) (<= 90 color 97)))
+                 color))
+         (setf (eat--t-face-fg face)
+               (face-foreground
+                (intern (format "eat-term-color-%i" (- color 82)))
+                nil t)))
+        (`(,(and (pred (lambda (color) (<= 100 color 107)))
+                 color))
+         (setf (eat--t-face-bg face)
+               (face-foreground
+                (intern (format "eat-term-color-%i" (- color 92)))
+                nil t)))))
+    ;; Update face according to the attributes.
+    (setf (eat--t-face-face face)
+          `(,@(when-let ((fg (or (if (eat--t-face-conceal face)
+                                     (eat--t-face-bg face)
+                                   (eat--t-face-fg face))
+                                 (cond
+                                  ((eat--t-face-inverse face)
+                                   (face-foreground 'default))
+                                  ((eat--t-face-conceal face)
+                                   (face-background 'default))))))
+                (list (if (eat--t-face-inverse face)
+                          :background
+                        :foreground)
+                      fg))
+            ,@(when-let ((bg (or (eat--t-face-bg face)
+                                 (and (eat--t-face-inverse face)
+                                      (face-background 'default)))))
+                (list (if (eat--t-face-inverse face)
+                          :foreground
+                        :background)
+                      bg))
+            ,@(when-let ((underline (eat--t-face-underline face)))
+                (list
+                 :underline
+                 (list :color (eat--t-face-underline-color face)
+                       :style underline)))
+            ,@(when-let ((crossed (eat--t-face-crossed face)))
+                ;; REVIEW: How about colors?  No terminal supports
+                ;; crossed attribute with colors, so we'll need to be
+                ;; creative to add the feature.
+                `(:strike-through t))
+            :inherit
+            (,@(when-let ((intensity (eat--t-face-intensity face)))
+                 (list intensity))
+             ,@(when-let ((italic (eat--t-face-italic face)))
+                 (cl-assert (1value (eq (1value italic)
+                                        'eat-term-italic)))
+                 (list (1value italic)))
+             ,@(when-let ((blink (eat--t-face-blink face)))
+                 (list blink))
+             ,(eat--t-face-font face))))))
+
+(defun eat--t-enable-keypad ()
+  "Enable keypad."
+  (1value (setf (eat--t-term-keypad-mode eat--t-term) t)))
+
+(defun eat--t-disable-keypad ()
+  "Disable keypad."
+  (1value (setf (eat--t-term-keypad-mode eat--t-term) nil)))
+
+(defun eat--t-enable-sgr-mouse-encoding ()
+  "Arrange that the following mouse events will be encoded like SGR."
+  (setf (eat--t-term-mouse-encoding eat--t-term) 'sgr))
+
+(defun eat--t-disable-sgr-mouse-encoding ()
+  "Arrange that the following mouse events won't be encoded like SGR."
+  (setf (eat--t-term-mouse-encoding eat--t-term) nil))
+
+(defun eat--t-set-mouse-mode (mode)
+  "Set current mouse mode to MODE.
+
+MODE should be one of nil and `x10', `normal', `button-event',
+`any-event'."
+  (setf (eat--t-term-mouse-mode eat--t-term) mode)
+  ;; When MODE is nil, disable mouse.
+  (unless mode
+    (eat--t-disable-sgr-mouse-encoding))
+  ;; `x10' mouse mode doesn't need to keep track of the mouse buttons
+  ;; pressed.
+  (when (or (not mode)
+            (eq mode 'x10))
+    (setf (eat--t-term-mouse-pressed eat--t-term) nil))
+  ;; Inform the UI.
+  (funcall (eat--t-term-grab-mouse-fn eat--t-term) eat--t-term
+           (pcase mode
+             ('x10 :click)
+             ('normal :modifier-click)
+             ('button-event :drag)
+             ('any-event :all))))
+
+(defun eat--t-enable-x10-mouse ()
+  "Enable X10 mouse tracking."
+  (eat--t-set-mouse-mode 'x10))
+
+(defun eat--t-enable-normal-mouse ()
+  "Enable normal mouse tracking."
+  (eat--t-set-mouse-mode 'normal))
+
+(defun eat--t-enable-button-event-mouse ()
+  "Enable button-event mouse tracking."
+  (eat--t-set-mouse-mode 'button-event))
+
+(defun eat--t-enable-any-event-mouse ()
+  "Enable any-event mouse tracking."
+  (eat--t-set-mouse-mode 'any-event))
+
+(defun eat--t-disable-mouse ()
+  "Disable mouse tracking."
+  (eat--t-set-mouse-mode nil))
+
+(defun eat--t-enable-focus-event ()
+  "Enable sending focus events."
+  (1value (setf (eat--t-term-focus-event-mode eat--t-term) t))
+  (funcall (eat--t-term-set-focus-ev-mode-fn eat--t-term) eat--t-term
+           t))
+
+(defun eat--t-disable-focus-event ()
+  "Disable sending focus events."
+  (1value (setf (eat--t-term-focus-event-mode eat--t-term) nil))
+  (funcall (eat--t-term-set-focus-ev-mode-fn eat--t-term) eat--t-term
+           nil))
+
+(defun eat--t-set-title (title)
+  "Set the title of terminal to TITLE."
+  ;; Update title.
+  (setf (eat--t-term-title eat--t-term) title)
+  ;; Inform the UI.
+  (funcall (eat--t-term-set-title-fn eat--t-term) eat--t-term title))
+
+(defun eat--t-send-device-attrs (params format)
+  "Return device attributes.
+
+PARAMS is the parameter list and FORMAT is the format of parameters in
+output."
+  (let ((params (or params '((0)))))
+    (pcase format
+      ('nil
+       (when (= (caar params) 0)
+         (funcall (eat--t-term-input-fn eat--t-term) eat--t-term
+                  "\e[?1;2c")))
+      (?>
+       (when (= (caar params) 0)
+         (funcall (eat--t-term-input-fn eat--t-term) eat--t-term
+                  "\e[>0;242;0c"))))))
+
+(defun eat--t-report-foreground-color ()
+  "Report the current default foreground color to the client."
+  (funcall
+   (eat--t-term-input-fn eat--t-term) eat--t-term
+   (let ((rgb (color-values (face-foreground 'default))))
+     (format "\e]10;%04x/%04x/%04x\e\\"
+             (pop rgb) (pop rgb) (pop rgb)))))
+
+(defun eat--t-report-background-color ()
+  "Report the current default background color to the client."
+  (funcall
+   (eat--t-term-input-fn eat--t-term) eat--t-term
+   (let ((rgb (color-values (face-background 'default))))
+     (format "\e]11;%04x/%04x/%04x\e\\"
+             (pop rgb) (pop rgb) (pop rgb)))))
+
+(defun eat--t-manipulate-selection (targets data)
+  "Set and send current selection.
+
+TARGETS is a string containing zero or more characters from the set
+`c', `p', `q', `s', `0', `1', `2', `3', `4', `5', `6', `7', `8', `9'.
+DATA is the selection data encoded in base64."
+  (when (string-empty-p targets)
+    (setq targets "s0"))
+  (if (string= data "?")
+      ;; The client is requesting for clipboard content, let's try to
+      ;; fulfill the request.
+      (funcall
+       (eat--t-term-input-fn eat--t-term) eat--t-term
+       (let ((str nil)
+             (source nil)
+             (n 0))
+         (while (and (not str) (< n (length targets)))
+           (setq
+            str
+            (pcase (aref targets n)
+              ;; c, p, q and s targets are handled by the UI, and they
+              ;; might refuse to give the clipboard content.
+              (?c
+               (funcall
+                (eat--t-term-manipulate-selection-fn eat--t-term)
+                eat--t-term :clipboard t))
+              (?p
+               (funcall
+                (eat--t-term-manipulate-selection-fn eat--t-term)
+                eat--t-term :primary t))
+              (?q
+               (funcall
+                (eat--t-term-manipulate-selection-fn eat--t-term)
+                eat--t-term :secondary t))
+              (?s
+               (funcall
+                (eat--t-term-manipulate-selection-fn eat--t-term)
+                eat--t-term :select t))
+              ;; 0 to 9 targets are handled by us, and always work.
+              ((and (pred (<= ?0))
+                    (pred (>= ?9))
+                    i)
+               (aref (eat--t-term-cut-buffers eat--t-term)
+                     (- i ?0)))))
+           ;; If we got a string to send, record the source to inform
+           ;; the client.
+           (when str
+             (setq source (string (aref targets n))))
+           (cl-incf n))
+         ;; No string to send, so send an empty string and an empty
+         ;; target string meaning that we don't have any answer.
+         (unless str
+           (setq str "")
+           (setq source ""))
+         (format "\e]52;%s;%s\e\\" source
+                 (base64-encode-string str))))
+    ;; The client is requesting to set clipboard content, let's try to
+    ;; fulfill the request.
+    (let ((str (ignore-error error
+                 (decode-coding-string (base64-decode-string data)
+                                       locale-coding-system))))
+      (seq-doseq (target targets)
+        (pcase target
+          ;; c, p, q and s targets are handled by the UI, and they
+          ;; might reject the new clipboard content.
+          (?c
+           (funcall (eat--t-term-manipulate-selection-fn eat--t-term)
+                    eat--t-term :clipboard str))
+          (?p
+           (funcall (eat--t-term-manipulate-selection-fn eat--t-term)
+                    eat--t-term :primary str))
+          (?q
+           (funcall (eat--t-term-manipulate-selection-fn eat--t-term)
+                    eat--t-term :secondary str))
+          (?s
+           (funcall (eat--t-term-manipulate-selection-fn eat--t-term)
+                    eat--t-term :select str))
+          ;; 0 to 9 targets are handled by us, and always work.
+          ((and (pred (<= ?0))
+                (pred (>= ?9))
+                i)
+           (aset (eat--t-term-cut-buffers eat--t-term) (- i ?0)
+                 str)))))))
+
+(defun eat--t-set-modes (params format)
+  "Set modes according to PARAMS in format FORMAT."
+  ;; Dispatch the request to appropriate function.
+  (pcase format
+    ('nil
+     (while params
+       (pcase (pop params)
+         ('(4)
+          (eat--t-insert-mode)))))
+    (??
+     (while params
+       (pcase (pop params)
+         ('(1)
+          (eat--t-enable-keypad))
+         ('(7)
+          (eat--t-enable-auto-margin))
+         ('(9)
+          (eat--t-enable-x10-mouse))
+         ('(12)
+          (eat--t-blinking-cursor))
+         ('(25)
+          (eat--t-default-cursor))
+         ('(1000)
+          (eat--t-enable-normal-mouse))
+         ('(1002)
+          (eat--t-enable-button-event-mouse))
+         ('(1003)
+          (eat--t-enable-any-event-mouse))
+         ('(1004)
+          (eat--t-enable-focus-event))
+         ('(1006)
+          (eat--t-enable-sgr-mouse-encoding))
+         ('(1048)
+          (eat--t-save-cur))
+         (`(,(or 1047 1049))
+          (eat--t-enable-alt-disp))
+         ('(2004)
+          (eat--t-enable-bracketed-yank)))))))
+
+(defun eat--t-reset-modes (params format)
+  "Reset modes according to PARAMS in format FORMAT."
+  ;; Dispatch the request to appropriate function.
+  (pcase format
+    ('nil
+     (while params
+       (pcase (pop params)
+         ('(4)
+          (eat--t-replace-mode)))))
+    (??
+     (while params
+       (pcase (pop params)
+         ('(1)
+          (eat--t-disable-keypad))
+         ('(7)
+          (eat--t-disable-auto-margin))
+         ('(12)
+          (eat--t-non-blinking-cursor))
+         ('(25)
+          (eat--t-invisible-cursor))
+         (`(,(or 9 1000 1002 1003))
+          (eat--t-disable-mouse))
+         ('(1004)
+          (eat--t-disable-focus-event))
+         ('(1006)
+          (eat--t-disable-sgr-mouse-encoding))
+         ('(1047)
+          (eat--t-disable-alt-disp 'dont-move-cursor))
+         ('(1048)
+          (eat--t-restore-cur))
+         ('(1049)
+          (eat--t-disable-alt-disp))
+         ('(2004)
+          (eat--t-disable-bracketed-yank)))))))
+
+(defun eat--t-handle-output (output)
+  "Parse and evaluate OUTPUT."
+  (let ((index 0))
+    (while (< index (length output))
+      (pcase (eat--t-term-parser-state eat--t-term)
+        ('nil
+         ;; Regular expression to find the end of plain text.
+         (let ((match (string-match
+                       (1value (rx (or ?\0 ?\a ?\b ?\t ?\n ?\v
+                                       ?\f ?\r ?\C-n ?\C-o ?\e
+                                       #x7f)))
+                       output index)))
+           (if (not match)
+               ;; The regex didn't match, so everything left to handle
+               ;; is just plain text.
+               (progn
+                 (eat--t-write (substring output index))
+                 (setq index (length output)))
+             (when (/= match index)
+               ;; The regex matched, and the position is after the
+               ;; current position.  Process the plain text between
+               ;; them and advance to the control sequence.
+               (eat--t-write (substring output index match))
+               (setq index match))
+             ;; Dispatch control sequence.
+             (cl-incf index)
+             (pcase (aref output (1- index))
+               (?\a
+                (eat--t-bell))
+               (?\b
+                (eat--t-cur-left 1))
+               (?\t
+                (eat--t-horizontal-tab 1))
+               (?\n
+                (eat--t-line-feed))
+               (?\v
+                (eat--t-index))
+               (?\f
+                (eat--t-form-feed))
+               (?\r
+                ;; Avoid going to line home just before a line feed,
+                ;; we can just insert a new line if we are at the
+                ;; end of display.
+                (unless (and (/= index (length output))
+                             (= (aref output index) ?\n))
+                  (eat--t-carriage-return)))
+               (?\C-n
+                (eat--t-change-charset 'g1))
+               (?\C-o
+                (eat--t-change-charset 'g0))
+               (?\e
+                (1value (setf (eat--t-term-parser-state eat--t-term)
+                              '(read-esc))))))))
+        ('(read-esc)
+         (let ((type (aref output index)))
+           (cl-incf index)
+           (1value (setf (eat--t-term-parser-state eat--t-term) nil))
+           ;; Dispatch control sequence.
+           (pcase type
+             ;; ESC (.
+             (?\(
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-standard g0 "")))
+             ;; ESC ).
+             (?\)
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-standard g1 "")))
+             ;; ESC *.
+             (?*
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-standard g2 "")))
+             ;; ESC +.
+             (?+
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-standard g3 "")))
+             ;; ESC -.
+             (?-
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-vt300 g1 "")))
+             ;; ESC ..
+             (?.
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-vt300 g2 "")))
+             ;; ESC /.
+             (?/
+              (setf (eat--t-term-parser-state eat--t-term)
+                    '(read-charset-vt300 g3 "")))
+             ;; ESC 7.
+             (?7
+              (eat--t-save-cur))
+             ;; ESC 8.
+             (?8
+              (eat--t-restore-cur))
+             ;; ESC D.
+             (?D
+              (eat--t-index))
+             ;; ESC E.
+             (?E
+              (eat--t-line-feed))
+             ;; ESC M.
+             (?M
+              (eat--t-reverse-index))
+             ;; ESC P, or DCS.
+             (?P
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-dcs ""))))
+             ;; ESC X, or SOS.
+             (?X
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-sos ""))))
+             ;; ESC [, or CSI.
+             (?\[
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-csi ""))))
+             ;; ESC ], or OSC.
+             (?\]
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-osc ""))))
+             ;; ESC ^, or PM.
+             (?^
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-pm ""))))
+             ;; ESC _, or APC.
+             (?_
+              (1value (setf (eat--t-term-parser-state eat--t-term)
+                            '(read-apc ""))))
+             ;; ESC c.
+             (?c
+              (eat--t-reset))
+             ;; ESC n.
+             (?n
+              (eat--t-change-charset 'g2))
+             ;; ESC o.
+             (?o
+              (eat--t-change-charset 'g3)))))
+        (`(read-csi ,buf)
+         (let ((match (string-match (rx (any (#x40 . #x7e)))
+                                    output index)))
+           (if (not match)
+               (progn
+                 (setf (eat--t-term-parser-state eat--t-term)
+                       `(read-csi ,(concat buf (substring output
+                                                          index))))
+                 (setq index (length output)))
+             (setf (eat--t-term-parser-state eat--t-term) nil)
+             (pcase
+                 (let ((str (concat buf (substring output index
+                                                   match)))
+                       (format nil)
+                       (intermediate-bytes ""))
+                   (save-match-data
+                     (when (string-match
+                            (rx (zero-or-more (any (?  . ?/)))
+                                string-end)
+                            str)
+                       (setq str (substring
+                                  str 0 (match-beginning 0)))
+                       (setq intermediate-bytes
+                             (match-string 0 str))))
+                   (when (and (not (string-empty-p str))
+                              (= (aref str 0) ??))
+                     (setq format ??)
+                     (setq str (substring str 1)))
+                   (when (and (not (string-empty-p str))
+                              (= (aref str 0) ?>))
+                     (setq format ?>)
+                     (setq str (substring str 1)))
+                   (when (and (not (string-empty-p str))
+                              (= (aref str 0) ?=))
+                     (setq format ?=)
+                     (setq str (substring str 1)))
+                   (setq index (match-end 0))
+                   (list
+                    (concat intermediate-bytes
+                            (match-string 0 output))
+                    format
+                    (cond
+                     ((string-empty-p str) '((nil)))
+                     ((<= #x30 (aref str 0) #x3b)
+                      (mapcar (lambda (p)
+                                (mapcar (lambda (s)
+                                          (unless (string-empty-p s)
+                                            (string-to-number s)))
+                                        (split-string p ":")))
+                              (split-string str ";")))
+                     (t str))))
+               ;; CSI <n> @.
+               (`("@" nil ,(and (pred listp) params))
+                (eat--t-insert-char (caar params)))
+               ;; CSI <n> A.
+               ;; CSI <n> k.
+               (`(,(or "A" "k") nil ,(and (pred listp) params))
+                (eat--t-cur-up (caar params)))
+               ;; CSI <n> B.
+               ;; CSI <n> e.
+               (`(,(or "B" "e") nil ,(and (pred listp) params))
+                (eat--t-cur-down (caar params)))
+               ;; CSI <n> C.
+               ;; CSI <n> a.
+               (`(,(or "C" "a") nil ,(and (pred listp) params))
+                (eat--t-cur-right (caar params)))
+               ;; CSI <n> D.
+               ;; CSI <n> j.
+               (`(,(or "D" "j") nil ,(and (pred listp) params))
+                (eat--t-cur-left (caar params)))
+               ;; CSI <n> E.
+               (`("E" nil ,(and (pred listp) params))
+                (eat--t-beg-of-prev-line (caar params)))
+               ;; CSI <n> F.
+               (`("F" nil ,(and (pred listp) params))
+                (eat--t-beg-of-next-line (caar params)))
+               ;; CSI <n> G.
+               ;; CSI <n> `.
+               (`(,(or "G" "`") nil ,(and (pred listp) params))
+                (eat--t-cur-horizontal-abs (caar params)))
+               ;; CSI <n> ; <m> H
+               ;; CSI <n> ; <m> f
+               (`(,(or "H" "f") nil ,(and (pred listp) params))
+                (eat--t-goto (caar params) (caadr params)))
+               ;; CSI <n> I.
+               (`("I" nil ,(and (pred listp) params))
+                (eat--t-horizontal-tab (caar params)))
+               ;; CSI <n> J.
+               (`("J" nil ,(and (pred listp) params))
+                (eat--t-erase-in-disp (caar params)))
+               ;; CSI <n> K.
+               (`("K" nil ,(and (pred listp) params))
+                (eat--t-erase-in-line (caar params)))
+               ;; CSI <n> L.
+               (`("L" nil ,(and (pred listp) params))
+                (eat--t-insert-line (caar params)))
+               ;; CSI <n> M.
+               (`("M" nil ,(and (pred listp) params))
+                (eat--t-delete-line (caar params)))
+               ;; CSI <n> P.
+               (`("P" nil ,(and (pred listp) params))
+                (eat--t-delete-char (caar params)))
+               ;; CSI <n> S.
+               (`("S" nil ,(and (pred listp) params))
+                (eat--t-scroll-up (caar params)))
+               ;; CSI <n> T.
+               (`("T" nil ,(and (pred listp) params))
+                (eat--t-scroll-down (caar params)))
+               ;; CSI <n> X.
+               (`("X" nil ,(and (pred listp) params))
+                (eat--t-erase-char (caar params)))
+               ;; CSI <n> Z.
+               (`("Z" nil ,(and (pred listp) params))
+                (eat--t-horizontal-backtab (caar params)))
+               ;; CSI <n> b.
+               (`("b" nil ,(and (pred listp) params))
+                (eat--t-repeat-last-char (caar params)))
+               ;; CSI <n> c.
+               ;; CSI > <n> c.
+               (`("c" ,format ,(and (pred listp) params))
+                (eat--t-send-device-attrs params format))
+               ;; CSI <n> d.
+               (`("d" nil ,(and (pred listp) params))
+                (eat--t-cur-vertical-abs (caar params)))
+               ;; CSI ... h.
+               ;; CSI ? ... h.
+               (`("h" ,format ,(and (pred listp) params))
+                (eat--t-set-modes params format))
+               ;; CSI ... l.
+               ;; CSI ? ... l.
+               (`("l" ,format ,(and (pred listp) params))
+                (eat--t-reset-modes params format))
+               ;; CSI ... m.
+               (`("m" nil ,(and (pred listp) params))
+                (eat--t-set-sgr-params params))
+               ;; CSI 6 n.
+               ('("n" nil ((6)))
+                (eat--t-device-status-report))
+               ;; CSI <n> ; <n> r.
+               (`("r" nil ,(and (pred listp) params))
+                (eat--t-change-scroll-region (caar params)
+                                             (caadr params)))
+               ;; CSI s.
+               (`("s" nil nil)
+                (eat--t-save-cur))
+               ;; CSI u.
+               (`("u" nil nil)
+                (eat--t-restore-cur))))))
+        (`(,(and (or 'read-dcs 'read-sos 'read-osc 'read-pm 'read-apc)
+                 state)
+           ,buf)
+         ;; Find the end of string.
+         (let ((match (string-match (if (eq state 'read-osc)
+                                        (rx (or ?\a ?\\))
+                                      (rx ?\\))
+                                    output index)))
+           (if (not match)
+               (progn
+                 ;; Not found, store the text to process it later when
+                 ;; we get the end of string.
+                 (setf (eat--t-term-parser-state eat--t-term)
+                       `(,state ,(concat buf (substring output
+                                                        index))))
+                 (setq index (length output)))
+             ;; Matched!  Get the string from the output and previous
+             ;; runs.
+             (let ((str (concat buf (substring output index
+                                               match))))
+               (setq index (match-end 0))
+               ;; Is it really the end of string?
+               (if (and (= (aref output match) ?\\)
+                        (not (or (zerop (length str))
+                                 (= (aref str (1- (length str)))
+                                    ?\e))))
+                   ;; No.  Push the '\' character to process later.
+                   (setf (eat--t-term-parser-state eat--t-term)
+                         `(,state ,(concat str "\\")))
+                 ;; Yes!  It's the end!  We can parse it.
+                 (when (= (aref output match) ?\\)
+                   (setq str (substring str 0 (1- (length str)))))
+                 (setf (eat--t-term-parser-state eat--t-term) nil)
+                 ;; Dispatch control sequence.
+                 (pcase state
+                   ('read-osc
+                    (pcase str
+                      ;; OSC 0 ; <t> ST.
+                      ;; OSC 2 ; <t> ST.
+                      ((rx string-start (or ?0 ?2) ?\;
+                           (let title (zero-or-more anything))
+                           string-end)
+                       (eat--t-set-title title))
+                      ;; OSC 10 ; ? ST.
+                      ("10;?"
+                       (eat--t-report-foreground-color))
+                      ;; OSC 11 ; ? ST.
+                      ("11;?"
+                       (eat--t-report-background-color))
+                      ;; OSC 52 ; <t> ; <s> ST.
+                      ((rx string-start "52;"
+                           (let targets
+                             (zero-or-more (any ?c ?p ?q ?s
+                                                (?0 . ?9))))
+                           ";"
+                           (let data (zero-or-more anything))
+                           string-end)
+                       (eat--t-manipulate-selection
+                        targets data))))))))))
+        (`(read-charset-standard ,slot ,buf)
+         ;; Find the end.
+         (let ((match (string-match (rx (any ?0 ?2 ?4 ?5 ?6 ?7 ?9 ?<
+                                             ?= ?> ?? ?A ?B ?C ?E ?H
+                                             ?K ?Q ?R ?Y ?Z ?f))
+                                    output index)))
+           (if (not match)
+               (progn
+                 ;; Not found, store the text to process it later when
+                 ;; we find the end.
+                 (setf (eat--t-term-parser-state eat--t-term)
+                       `(read-charset-standard
+                         ,slot ,(concat buf (substring
+                                             output index))))
+                 (setq index (length output)))
+             ;; Got the end!
+             (let ((str (concat buf (substring output index
+                                               (match-end 0)))))
+               (setq index (match-end 0))
+               (setf (eat--t-term-parser-state eat--t-term) nil)
+               ;; Set the character set.
+               (eat--t-set-charset
+                slot
+                (pcase str
+                  ;; ESC ( 0.
+                  ;; ESC ) 0.
+                  ;; ESC * 0.
+                  ;; ESC + 0.
+                  ("0" 'dec-line-drawing)
+                  ;; ESC ( B.
+                  ;; ESC ) B.
+                  ;; ESC * B.
+                  ;; ESC + B.
+                  ("B" 'us-ascii)))))))
+        (`(read-charset-vt300 ,_slot)
+         (let ((_charset (aref output index)))
+           (cl-incf index)
+           (setf (eat--t-term-parser-state eat--t-term) nil)
+           (pcase charset
+             ;; TODO: Currently ignored.  It is here just to recognize
+             ;; the control sequence.
+             )))))))
+
+(defun eat--t-resize (width height)
+  "Resize terminal to WIDTH x HEIGHT."
+  (let* ((disp (eat--t-term-display eat--t-term))
+         (cursor (eat--t-disp-cursor disp))
+         (old-width (eat--t-disp-width disp))
+         (old-height (eat--t-disp-height disp)))
+    ;; Don't do anything if size hasn't changed, or the new size is
+    ;; too small.
+    (when (and (not (and (eq old-width width)
+                         (eq old-height height)))
+               (>= width 1)
+               (>= height 1))
+      ;; Update state.
+      (setf (eat--t-disp-width disp) width)
+      (setf (eat--t-disp-height disp) height)
+      (setf (eat--t-term-scroll-begin eat--t-term) 1)
+      (setf (eat--t-term-scroll-end eat--t-term)
+            (eat--t-disp-height disp))
+      (set-marker (eat--t-cur-position cursor) (point))
+      (if (eat--t-term-main-display eat--t-term)
+          ;; For alternative display, just delete the part of the
+          ;; display that went out of the edges.  So if the terminal
+          ;; was enlarged, we don't have anything to do.
+          (when (or (< width old-width)
+                    (< height old-height))
+            ;; Go to the beginning of display.
+            (goto-char (eat--t-disp-begin disp))
+            (dotimes (l height)
+              (eat--t-col-motion width)
+              (delete-region (point) (car (eat--t-eol)))
+              (if (< (1+ l) height)
+                  (forward-char)
+                (delete-region (point) (point-max))
+                (let ((y (eat--t-cur-y cursor))
+                      (x (eat--t-cur-x cursor)))
+                  (eat--t-goto 1 1)
+                  (eat--t-goto y x)))))
+        ;; REVIEW: This works, but it is very simple.  Most
+        ;; terminals have more sophisticated mechanisms to do this.
+        ;; It would be nice thing have them here.
+        ;; Go to the beginning of display.
+        (goto-char (eat--t-disp-begin disp))
+        ;; Try to move to the end of previous line, maybe that's a
+        ;; part of a too long line.
+        (unless (bobp)
+          (backward-char))
+        ;; Join all long lines.
+        (while (not (eobp))
+          (eat--t-join-long-line))
+        ;; Go to display beginning again and break long lines.
+        (goto-char (eat--t-disp-begin disp))
+        (while (not (eobp))
+          (eat--t-break-long-line (eat--t-disp-width disp)))
+        ;; Calculate the beginning position of display.
+        (goto-char (point-max))
+        ;; TODO: This part needs explanation.
+        (let* ((disp-begin (car (eat--t-bol (- (1- height))))))
+          (when (< (eat--t-disp-begin disp) disp-begin)
+            (goto-char (max (- (eat--t-disp-begin disp) 1)
+                            (point-min)))
+            (set-marker (eat--t-disp-begin disp) disp-begin)
+            (while (< (point) (1- (eat--t-disp-begin disp)))
+              (eat--t-join-long-line
+               (1- (eat--t-disp-begin disp))))))
+        ;; Update the cursor if needed.
+        (when (< (eat--t-cur-position cursor)
+                 (eat--t-disp-begin disp))
+          (set-marker (eat--t-cur-position cursor)
+                      (eat--t-disp-begin disp)))
+        ;; Update the coordinates of cursor.
+        (goto-char (eat--t-cur-position cursor))
+        (setf (eat--t-cur-x cursor) (1+ (eat--t-current-col)))
+        (goto-char (eat--t-disp-begin disp))
+        (setf (eat--t-cur-y cursor)
+              (let ((y 0))
+                (while (< (point) (eat--t-cur-position cursor))
+                  (condition-case nil
+                      (search-forward
+                       "\n" (eat--t-cur-position cursor))
+                    (search-failed
+                     (goto-char (eat--t-cur-position cursor))))
+                  (cl-incf y))
+                (when (or (= (point) (point-min))
+                          (= (char-before) ?\n))
+                  (cl-incf y))
+                (max y 1)))))))
+
+;;;###autoload
+(defun eat-term-make (buffer position)
+  "Make a Eat terminal at POSITION in BUFFER."
+  (eat--t-make-term
+   :buffer buffer
+   :begin (copy-marker position t)
+   :end (copy-marker position)
+   :display (eat--t-make-disp
+             :begin (copy-marker position)
+             :old-begin (copy-marker position)
+             :cursor (eat--t-make-cur
+                      :position (copy-marker position)))))
+
+(defmacro eat--t-with-env (terminal &rest body)
+  "Setup the environment for TERMINAL and eval BODY in it."
+  (declare (indent 1))
+  `(let ((eat--t-term ,terminal))
+     (with-current-buffer (eat--t-term-buffer eat--t-term)
+       (save-excursion
+         (save-restriction
+           (narrow-to-region (eat--t-term-begin eat--t-term)
+                             (eat--t-term-end eat--t-term))
+           (goto-char (eat--t-cur-position
+                       (eat--t-disp-cursor
+                        (eat--t-term-display eat--t-term))))
+           (unwind-protect
+               (progn ,@body)
+             (set-marker (eat--t-cur-position
+                          (eat--t-disp-cursor
+                           (eat--t-term-display eat--t-term)))
+                         (point))
+             (set-marker (eat--t-term-begin eat--t-term) (point-min))
+             (set-marker (eat--t-term-end eat--t-term)
+                         (point-max))))))))
+
+(defun eat-term-delete (terminal)
+  "Delete TERMINAL and do any cleanup to do."
+  (let ((inhibit-quit t)
+        (eat--t-term terminal))
+    (with-current-buffer (eat--t-term-buffer eat--t-term)
+      (save-excursion
+        (save-restriction
+          (narrow-to-region (eat--t-term-begin eat--t-term)
+                            (eat--t-term-end eat--t-term))
+          (eat--t-set-cursor-state :default)
+          ;; Go to the beginning of display.
+          (goto-char (eat--t-disp-begin
+                      (eat--t-term-display eat--t-term)))
+          ;; Join all long lines.
+          (unless (bobp)
+            (backward-char))
+          (while (not (eobp))
+            (eat--t-join-long-line)))))))
+
+(defun eat-term-reset (terminal)
+  "Reset TERMINAL."
+  (let ((inhibit-quit t))
+    (eat--t-with-env terminal
+      (eat--t-reset))))
+
+(defun eat-term-input-function (terminal)
+  "Return the function used to send input from TERMINAL.
+
+The function is called with two arguments, TERMINAL and the string to
+send.  The function should not change point and buffer restriction.
+
+To set it, use (`setf' (`eat-term-input-function' TERMINAL) FUNCTION),
+where FUNCTION is the input function."
+  (eat--t-term-input-fn terminal))
+
+(gv-define-setter eat-term-input-function (function terminal)
+  `(setf (eat--t-term-input-fn ,terminal) ,function))
+
+(defun eat-term-cursor-type (terminal)
+  "Return the cursor state of TERMINAL.
+
+The return value can be one of the following:
+
+  `:default'            Default cursor.
+  `:invisible'          Invisible cursor.
+  `:very-visible'       Very visible cursor."
+  (eat--t-term-cur-state terminal))
+
+(defun eat-term-set-cursor-function (terminal)
+  "Return the function used to set the cursor of TERMINAL.
+
+The function is called with two arguments, TERMINAL and a symbol STATE
+describing the new state of cursor.  The function should not change
+point and buffer restriction.  STATE can be one of the following:
+
+  `:default'            Default cursor.
+  `:invisible'          Invisible cursor.
+  `:very-visible'       Very visible cursor.  Can also be implemented
+                        as blinking cursor.
+
+More possible values might be added in future.  So in case the
+function doesn't know about a particular cursor state, it should reset
+the cursor to the default like the `:default' state.
+
+To set it, use (`setf' (`eat-term-set-cursor-function' TERMINAL)
+FUNCTION), where FUNCTION is the function to set cursor."
+  (eat--t-term-set-cursor-fn terminal))
+
+(gv-define-setter eat-term-set-cursor-function (function terminal)
+  `(setf (eat--t-term-set-cursor-fn ,terminal) ,function))
+
+(defun eat-term-title (terminal)
+  "Return the current title of TERMINAL."
+  (eat--t-term-title terminal))
+
+(defun eat-term-set-title-function (terminal)
+  "Return the function used to set the title of TERMINAL.
+
+The function is called with two arguments, TERMINAL and the new title
+of TERMINAL.  The function should not change point and buffer
+restriction.
+
+To set it, use (`setf' (`eat-term-set-title-function' TERMINAL)
+FUNCTION), where FUNCTION is the function to set title."
+  (eat--t-term-set-title-fn terminal))
+
+(gv-define-setter eat-term-set-title-function (function terminal)
+  `(setf (eat--t-term-set-title-fn ,terminal) ,function))
+
+(defun eat-term-grab-mouse-function (terminal)
+  "Return the function used to grab the mouse.
+
+The function is called with two arguments, TERMINAL and a symbol MODE
+describing the new mouse mode MODE.  The function should not change
+point and buffer restriction.  MODE can be one of the following:
+
+  nil                 Disable mouse.
+  `:click'              Pass `mouse-1', `mouse-2', and `mouse-3'
+                        clicks.
+  `:modifier-click'     Pass all mouse click events on both press and
+                        release, including `control', `meta' and
+                        `shift' modifiers.
+  `:drag'               All of `:modifier-click', plus dragging
+                        (moving mouse while pressed) information.
+  `:all'                Pass all mouse events, including movement.
+
+More possible values might be added in future.  So in case the
+function doesn't know about a particular mouse mode, it should behave
+as if MODE was nil and disable mouse.
+
+To set it, use (`setf' (`eat-term-set-mouse-mode-function' TERMINAL)
+FUNCTION), where FUNCTION is the function to set mouse mode."
+  (eat--t-term-grab-mouse-fn terminal))
+
+(gv-define-setter eat-term-grab-mouse-function (function terminal)
+  `(setf (eat--t-term-grab-mouse-fn ,terminal) ,function))
+
+(defun eat-term-grab-focus-events-function (terminal)
+  "Return the function used to grab focus in and out events.
+
+The function is called with two arguments, TERMINAL and a boolean
+describing the new grabbing mode.  When the boolean is nil, don't send
+focus event, otherwise send focus events.  The function should not
+change point and buffer restriction.
+
+To set it, use (`setf' (`eat-term-grab-focus-events-function'
+TERMINAL) FUNCTION), where FUNCTION is the function to grab focus
+events."
+  (eat--t-term-set-focus-ev-mode-fn terminal))
+
+(gv-define-setter eat-term-grab-focus-events-function
+    (function terminal)
+  `(setf (eat--t-term-set-focus-ev-mode-fn ,terminal) ,function))
+
+(defun eat-term-manipulate-selection-function (terminal)
+  "Return the function used to manipulate selection (or `kill-ring').
+
+The function is called with three arguments, TERMINAL, a symbol
+SELECTION describing the selection paramater and DATA, a string, or a
+boolean.  The function should not change point and buffer restriction.
+SELECTION can be one of `:clipboard', `:primary', `:secondary',
+`:select'.  When DATA is a string, it should set the selection to that
+string, when DATA is nil, it should unset the selection, and when DATA
+is t, it should return the selection, or nil if none.
+
+To set it, use (`setf' (`eat-term-manipulate-selection-function'
+TERMINAL) FUNCTION), where FUNCTION is the function to manipulate
+selection."
+  (eat--t-term-manipulate-selection-fn terminal))
+
+(gv-define-setter eat-term-manipulate-selection-function
+    (function terminal)
+  `(setf (eat--t-term-manipulate-selection-fn ,terminal) ,function))
+
+(defun eat-term-ring-bell-function (terminal)
+  "Return the function used to ring the bell.
+
+The function is called with a single argument TERMINAL.
+
+To set it, use (`setf' (`eat-term-ring-bell-function' TERMINAL)
+FUNCTION), where FUNCTION is the function to ring the bell."
+  (eat--t-term-manipulate-selection-fn terminal))
+
+(gv-define-setter eat-term-ring-bell-function (function terminal)
+  `(setf (eat--t-term-bell-fn ,terminal) ,function))
+
+(defun eat-term-size (terminal)
+  "Return the size of TERMINAL as (WIDTH . HEIGHT)."
+  (let ((disp (eat--t-term-display terminal)))
+    (cons (eat--t-disp-width disp) (eat--t-disp-height disp))))
+
+(defun eat-term-beginning (terminal)
+  "Return the beginning position of TERMINAL.
+
+Don't use markers to store the position, call this function whenever
+you need the position."
+  (eat--t-term-begin terminal))
+
+(defun eat-term-end (terminal)
+  "Return the end position of TERMINAL.
+
+This is also the end position of TERMINAL's display.
+
+Don't use markers to store the position, call this function whenever
+you need the position."
+  (eat--t-term-end terminal))
+
+(defun eat-term-display-beginning (terminal)
+  "Return the beginning position of TERMINAL's display."
+  (eat--t-disp-begin (eat--t-term-display terminal)))
+
+(defun eat-term-display-cursor (terminal)
+  "Return the cursor's current position on TERMINAL's display."
+  (let* ((disp (eat--t-term-display terminal))
+         (cursor (eat--t-disp-cursor disp)))
+    ;; The cursor might be after the edge of the display.  But we
+    ;; don't want the UI to show that, so show cursor at the edge.
+    (if (> (eat--t-cur-x cursor) (eat--t-disp-width disp))
+        (1- (eat--t-cur-position cursor))
+      (eat--t-cur-position cursor))))
+
+(defun eat-term-process-output (terminal output)
+  "Process OUTPUT from client and show it on TERMINAL's display."
+  (let ((inhibit-quit t))
+    (eat--t-with-env terminal
+      (eat--t-handle-output output))))
+
+(defun eat-term-redisplay (terminal)
+  "Prepare TERMINAL for displaying."
+  (let ((inhibit-quit t))
+    (eat--t-with-env terminal
+      (let* ((disp (eat--t-term-display eat--t-term)))
+        (when (< (eat--t-disp-old-begin disp)
+                 (eat--t-disp-begin disp))
+          ;; Join long lines.
+          (let ((limit (copy-marker (1- (eat--t-disp-begin disp)))))
+            (save-excursion
+              (goto-char (max (1- (eat--t-disp-old-begin disp))
+                              (point-min)))
+              (while (< (point) limit)
+                (eat--t-join-long-line limit))))
+          ;; Truncate scrollback.
+          (when eat-term-scrollback-size
+            (delete-region
+             (point-min)
+             (max (point-min) (- (point) eat-term-scrollback-size))))
+          (set-marker (eat--t-disp-old-begin disp)
+                      (eat--t-disp-begin disp)))))))
+
+(defun eat-term-resize (terminal width height)
+  "Resize TERMINAL to WIDTH x HEIGHT."
+  (let ((inhibit-quit t))
+    (eat--t-with-env terminal
+      (eat--t-resize width height))))
+
+(defun eat-term-in-alternative-display-p (terminal)
+  "Return non-nil when TERMINAL is in alternative display mode."
+  (eat--t-term-main-display terminal))
+
+(defun eat-term-input-event (terminal n event &optional ref-pos)
+  "Send EVENT as input N times to TERMINAL.
+
+EVENT should be a event.  It can be any standard Emacs event, or a
+event list of any of the following forms:
+
+  (eat-focus-in)
+    Terminal just gained focus.
+
+  (eat-focus-out)
+    Terminal just lost focus.
+
+REF-POS is a mouse position list pointing to the start of terminal
+display satisfying the predicate `posnp'.  It is used to calculate the
+position of mouse events and `eat-mouse-drag' events on terminal when
+given.
+
+For mouse events, events should be sent on both mouse button press and
+release unless the mouse grabing mode is `:click', otherwise the
+client process may get confused."
+  (let ((disp (eat--t-term-display terminal)))
+    (cl-flet ((send (str)
+                (funcall (eat--t-term-input-fn terminal)
+                         terminal str)))
+      (dotimes (_ (or n 1))
+        (pcase event
+          ;; Arrow key, `insert', `delete', `deletechar', `home',
+          ;; `end', `prior', `next' and their modifier variants.
+          ((and (or 'up 'down 'right 'left
+                    'C-up 'C-down 'C-right 'C-left
+                    'M-up 'M-down 'M-right 'M-left
+                    'S-up 'S-down 'S-right 'S-left
+                    'C-M-up 'C-M-down 'C-M-right 'C-M-left
+                    'C-S-up 'C-S-down 'C-S-right 'C-S-left
+                    'M-S-up 'M-S-down 'M-S-right 'M-S-left
+                    'C-M-S-up 'C-M-S-down 'C-M-S-right 'C-M-S-left
+                    'insert 'C-insert 'M-insert 'S-insert 'C-M-insert
+                    'C-S-insert 'M-S-insert 'C-M-S-insert
+                    'delete 'C-delete 'M-delete 'S-delete 'C-M-delete
+                    'C-S-delete 'M-S-delete 'C-M-S-delete
+                    'deletechar 'C-deletechar 'M-deletechar
+                    'S-deletechar 'C-M-deletechar 'C-S-deletechar
+                    'M-S-deletechar 'C-M-S-deletechar
+                    'home 'C-home 'M-home 'S-home 'C-M-home 'C-S-home
+                    'M-S-home 'C-M-S-home
+                    'end 'C-end 'M-end 'S-end 'C-M-end 'C-S-end
+                    'M-S-end 'C-M-S-end
+                    'prior 'C-prior 'M-prior 'S-prior 'C-M-prior
+                    'C-S-prior 'M-S-prior 'C-M-S-prior
+                    'next 'C-next 'M-next 'S-next 'C-M-next 'C-S-next
+                    'M-S-next 'C-M-S-next)
+                ev)
+           (send
+            (format
+             "\e%s%c"
+             (if (not (or (memq 'control (event-modifiers ev))
+                          (memq 'meta (event-modifiers ev))
+                          (memq 'shift (event-modifiers ev))))
+                 (pcase (event-basic-type ev)
+                   ('insert "[2")
+                   ((or 'delete 'deletechar) "[3")
+                   ('prior "[5")
+                   ('next "[6")
+                   (_ (if (eat--t-term-keypad-mode terminal)
+                          "O"
+                        "[")))
+               (format
+                "[%c;%c"
+                (pcase (event-basic-type ev)
+                  ('insert ?2)
+                  ((or 'delete 'deletechar) ?3)
+                  ('prior ?5)
+                  ('next ?6)
+                  (_ ?1))
+                (pcase (event-modifiers ev)
+                  ((and (pred (memq 'control))
+                        (pred (memq 'meta))
+                        (pred (memq 'shift)))
+                   ?8)
+                  ((and (pred (memq 'control))
+                        (pred (memq 'meta)))
+                   ?7)
+                  ((and (pred (memq 'control))
+                        (pred (memq 'shift)))
+                   ?6)
+                  ((and (pred (memq 'meta))
+                        (pred (memq 'shift)))
+                   ?4)
+                  ((pred (memq 'control))
+                   ?5)
+                  ((pred (memq 'meta))
+                   ?3)
+                  ((pred (memq 'shift))
+                   ?2))))
+             (pcase (event-basic-type ev)
+               ('up ?A)
+               ('down ?B)
+               ('right ?C)
+               ('left ?D)
+               ('home ?H)
+               ('end ?F)
+               (_ ?~)))))
+          ('backspace
+           (send "\C-?"))
+          ('C-backspace
+           (send "\C-h"))
+          ;; Function keys.
+          ((and (pred symbolp)
+                fn-key
+                (let (rx string-start "f"
+                         (let fn-num (one-or-more (any (?0 . ?9))))
+                         string-end)
+                  (symbol-name fn-key))
+                (let (and (pred (<= 1))
+                          (pred (>= 63))
+                          key)
+                  (string-to-number fn-num)))
+           (send
+            (aref
+             ["\eOP" "\eOQ" "\eOR" "\eOS" "\e[15~" "\e[17~" "\e[18~"
+              "\e[19~" "\e[20~" "\e[21~" "\e[23~" "\e[24~" "\e[1;2P"
+              "\e[1;2Q" "\e[1;2R" "\e[1;2S" "\e[15;2~" "\e[17;2~"
+              "\e[18;2~" "\e[19;2~" "\e[20;2~" "\e[21;2~" "\e[23;2~"
+              "\e[24;2~" "\e[1;5P" "\e[1;5Q" "\e[1;5R" "\e[1;5S"
+              "\e[15;5~" "\e[17;5~" "\e[18;5~" "\e[19;5~" "\e[20;5~"
+              "\e[21;5~" "\e[23;5~" "\e[24;5~" "\e[1;6P" "\e[1;6Q"
+              "\e[1;6R" "\e[1;6S" "\e[15;6~" "\e[17;6~" "\e[18;6~"
+              "\e[19;6~" "\e[20;6~" "\e[21;6~" "\e[23;6~" "\e[24;6~"
+              "\e[1;3P" "\e[1;3Q" "\e[1;3R" "\e[1;3S" "\e[15;3~"
+              "\e[17;3~" "\e[18;3~" "\e[19;3~" "\e[20;3~" "\e[21;3~"
+              "\e[23;3~" "\e[24;3~" "\e[1;4P" "\e[1;4Q" "\e[1;4R"]
+             (1- key))))
+          ((and (or (pred numberp)
+                    (pred symbolp))
+                char)
+           ;; Adapted from Term source.
+           (when (symbolp char)
+             ;; Convert `return' to C-m, etc.
+             (let ((tmp (get char 'event-symbol-elements)))
+               (if tmp (setq char (car tmp)))
+               (and (symbolp char)
+                    (setq tmp (get char 'ascii-character))
+                    (setq char tmp))))
+           (when (numberp char)
+             (let* ((base (event-basic-type char))
+                    (mods (event-modifiers char)))
+               ;; Try to avoid event-convert-list if possible.
+               (if (and (characterp char)
+                        (not (memq 'meta mods))
+                        (not (and (memq 'control mods)
+                                  (memq 'shift mods))))
+                   (send (format "%c" char))
+                 (when (memq 'control mods)
+                   (setq mods (delq 'shift mods)))
+                 (let ((ch (pcase (event-convert-list
+                                   (append (remq 'meta mods)
+                                           (list base)))
+                             (?\C-\  ?\C-@)
+                             (?\C-/ ?\C-?)
+                             (?\C-- ?\C-_)
+                             (c c))))
+                   (when (characterp ch)
+                     (send (cond
+                            ((and (memq 'meta mods)
+                                  (memq ch '(?\[ ?O)))
+                             "\e")
+                            (t
+                             (format
+                              (if (memq 'meta mods) "\e%c" "%c")
+                              ch))))))))))
+          ;; Mouse handling.
+          ((and (guard (eat--t-term-mouse-mode terminal))
+                mouse
+                (pred eventp)
+                (or (and (let mouse-type (event-basic-type mouse))
+                         (let (rx string-start "mouse-"
+                                  (let key-num (one-or-more
+                                                (any (?0 . ?9))))
+                                  string-end)
+                           (symbol-name mouse-type))
+                         (let (and (pred (<= 1))
+                                   (pred (>= 11))
+                                   mouse-num)
+                           (string-to-number key-num)))
+                    (and (let 'wheel-up (event-basic-type mouse))
+                         (let mouse-num 4))
+                    (and (let 'wheel-down (event-basic-type mouse))
+                         (let mouse-num 5))
+                    (and (let 'wheel-right (event-basic-type mouse))
+                         (let mouse-num 6))
+                    (and (let 'wheel-left (event-basic-type mouse))
+                         (let mouse-num 7))))
+           (let* ((modifiers (event-modifiers mouse))
+                  (pos (if (memq 'drag modifiers)
+                           (event-end mouse)
+                         (event-start mouse)))
+                  (x-y (posn-col-row pos 'use-window))
+                  (x (1+ (car x-y)))
+                  (y (1+ (cdr x-y)))
+                  (button
+                   (let ((b (aref
+                             [0 1 2 64 65 66 67 128 129 130 131]
+                             (1- mouse-num))))
+                     (when (memq 'shift modifiers)
+                       (cl-incf b 4))
+                     (when (memq 'meta modifiers)
+                       (cl-incf b 8))
+                     (when (memq 'control modifiers)
+                       (cl-incf b 16))
+                     b)))
+             (when ref-pos
+               (let ((ref-x-y (posn-col-row ref-pos 'use-window)))
+                 (cl-decf x (car ref-x-y))
+                 (cl-decf y (cdr ref-x-y))))
+             (when (and (<= 1 x (eat--t-disp-width disp))
+                        (<= 1 y (eat--t-disp-height disp))
+                        (or (eat--t-term-mouse-encoding terminal)
+                            (and (<= x 95)
+                                 (<= y 95)
+                                 (<= button 95))))
+               (if (eq (eat--t-term-mouse-mode terminal) 'x10)
+                   (when (and (< button 3)
+                              (or (memq 'click modifiers)
+                                  (memq 'drag modifiers)))
+                     (send
+                      (if (eq (eat--t-term-mouse-encoding terminal)
+                              'sgr)
+                          (format "\e[<%i;%i;%iM" button x y)
+                        (format "\e[M%c%c%c" (+ button 32) (+ x 32)
+                                (+ y 32)))))
+                 (cond
+                  ;; `down-mouse-1' and friends.
+                  ((memq 'down modifiers)
+                   ;; For `mouse-1', `mouse-2' and `mouse-3', keep
+                   ;; track the button's state, we'll need it when
+                   ;; button event mouse mode is enabled.
+                   (when (< (logand button 3) 3)
+                     (setf (eat--t-term-mouse-pressed terminal)
+                           ;; In XTerm and Kitty, mouse-1 is
+                           ;; prioritized over mouse-2, and mouse-2
+                           ;; over mouse-3.  However St doesn't keep
+                           ;; track of multiple buttons.
+                           (sort
+                            (cons button (eat--t-term-mouse-pressed
+                                          terminal))
+                            #'<)))
+                   (send
+                    (if (eq (eat--t-term-mouse-encoding terminal)
+                            'sgr)
+                        (format "\e[<%i;%i;%iM" button x y)
+                      (format "\e[M%c%c%c" (+ button 32) (+ x 32)
+                              (+ y 32)))))
+                  ;; `mouse-1', `mouse-2', `mouse-3', and their
+                  ;; `drag'ged variants.
+                  ((and (or (memq 'click modifiers)
+                            (memq 'drag modifiers))
+                        (<= mouse-num 3))
+                   ;; For `mouse-1', `mouse-2' and `mouse-3', keep
+                   ;; track the button's state, we'll need it when
+                   ;; button event mouse mode is enabled.
+                   (setf (eat--t-term-mouse-pressed terminal)
+                         (cl-delete-if
+                          (lambda (b)
+                            (= (logand b 3) (logand button 3)))
+                          (eat--t-term-mouse-pressed terminal)))
+                   (send
+                    (if (eq (eat--t-term-mouse-encoding terminal)
+                            'sgr)
+                        (format "\e[<%i;%i;%im" button x y)
+                      (format "\e[M%c%c%c" (+ (logior button 3) 32)
+                              (+ x 32) (+ y 32)))))
+                  ;; Mouse wheel, `mouse-4' and friends.
+                  (t
+                   (send
+                    (if (eq (eat--t-term-mouse-encoding terminal)
+                            'sgr)
+                        (format "\e[<%i;%i;%iM" button x y)
+                      (format "\e[M%c%c%c" (+ button 32) (+ x 32)
+                              (+ y 32))))))))))
+          ;; Mouse movement tracking.
+          ((and (guard (memq (eat--t-term-mouse-mode terminal)
+                             '(button-event any-event)))
+                (pred mouse-movement-p)
+                movement)
+           (let* ((pos (event-start movement))
+                  (x (1+ (car (posn-col-row pos))))
+                  (y (1+ (cdr (posn-col-row pos))))
+                  (button
+                   (if (car (eat--t-term-mouse-pressed terminal))
+                       (+ (car (eat--t-term-mouse-pressed terminal))
+                          32)
+                     35)))
+             (when ref-pos
+               (cl-decf x (car (posn-col-row ref-pos)))
+               (cl-decf y (cdr (posn-col-row ref-pos))))
+             (when (and (or (eq (eat--t-term-mouse-mode terminal)
+                                'any-event)
+                            (/= button 35))
+                        (<= 1 x (eat--t-disp-width disp))
+                        (<= 1 y (eat--t-disp-height disp))
+                        (or (eat--t-term-mouse-encoding terminal)
+                            (and (<= x 95)
+                                 (<= y 95)
+                                 (<= button 95))))
+               (send
+                (if (eq (eat--t-term-mouse-encoding terminal)
+                        'sgr)
+                    (format "\e[<%i;%i;%iM" button x y)
+                  (format "\e[M%c%c%c" (+ button 32) (+ x 32)
+                          (+ y 32)))))))
+          ;; Focus events.
+          ('(eat-focus-in)
+           (when (eat--t-term-focus-event-mode terminal)
+             (send "\e[I")))
+          ('(eat-focus-out)
+           (when (eat--t-term-focus-event-mode terminal)
+             (send "\e[O"))))))))
+
+(defun eat-send-string-as-yank (terminal args)
+  "Send ARGS to TERMINAL, honoring bracketed yank mode.
+
+Each argument in ARGS can be either string or character."
+  (funcall (eat--t-term-input-fn terminal) terminal
+           (let ((str (mapconcat (lambda (s)
+                                   (if (stringp s) s (string s)))
+                                 args "")))
+             (if (eat--t-term-bracketed-yank terminal)
+                 ;; REVIEW: What if `str' itself contains these escape
+                 ;; sequences?  St doesn't care and just wraps the
+                 ;; string with these magic escape sequences, while
+                 ;; Kitty tries to be smart.
+                 (format "\e[200~%s\e[201~" str)
+               str))))
+
+(defun eat-term-make-keymap (input-command categories exceptions)
+  "Make a keymap binding INPUT-COMMAND to the events of CATEGORIES.
+
+CATEGORIES is a list whose elements should be a one of the following
+keywords:
+
+  `:ascii'              All self-insertable characters, plus
+                        `backspace', `insert', `delete' and
+                        `deletechar' keys, with all possible
+                        modifiers.
+  `:arrow'              Arrow keys with all possible modifiers.
+  `:navigation'         Navigation keys: home, end, prior (or page up)
+                        and next (or page down) with all possible
+                        modifiers.
+  `:function'           Function keys (f1 - f63).
+  `:mouse-click'        `mouse-1', `mouse-2' and `mouse-3'.
+  `:mouse-modifier'     All mouse events except mouse movement.
+  `:mouse-movement'     Mouse movement.
+
+EXCEPTIONS is a list of key sequences to not bind.  Don't use
+\"M-...\" key sequences in EXCEPTIONS, use \"ESC ...\" instead."
+  (let ((map (make-sparse-keymap)))
+    (cl-labels ((bind (key)
+                  (unless (member key exceptions)
+                    (define-key map key input-command))))
+      (when (memq :ascii categories)
+        ;; Bind ASCII and self-insertable characters except ESC and
+        ;; DEL.
+        (bind [remap self-insert-command])
+        (cl-loop
+         for i from ?\C-@ to ?~
+         do (unless (= i meta-prefix-char)
+              (bind `[,i])))
+        ;; Bind `backspace', `delete', `deletechar', and all modified
+        ;; variants.
+        (dolist (key '( backspace C-backspace
+                        insert C-insert M-insert S-insert C-M-insert
+                        C-S-insert M-S-insert C-M-S-insert
+                        delete C-delete M-delete S-delete C-M-delete
+                        C-S-delete M-S-delete C-M-S-delete
+                        deletechar C-deletechar M-deletechar
+                        S-deletechar C-M-deletechar C-S-deletechar
+                        M-S-deletechar C-M-S-deletechar))
+          (bind `[,key]))
+        ;; Bind these non-encodable keys.  They are translated.
+        (dolist (key '(?\C-- ?\C-? ?\C-\ ))
+          (bind `[,key]))
+        ;; Bind M-<ASCII> keys.
+        (unless (member `[,meta-prefix-char] exceptions)
+          (define-key map `[,meta-prefix-char] (make-sparse-keymap))
+          (cl-loop
+           for i from ?\C-@ to ?~
+           do (unless (memq i '(?O ?\[))
+                (bind `[,meta-prefix-char ,i])))
+          (bind `[,meta-prefix-char ,meta-prefix-char])))
+      (when (memq :arrow categories)
+        (dolist (key '( up down right left
+                        C-up C-down C-right C-left
+                        M-up M-down M-right M-left
+                        S-up S-down S-right S-left
+                        C-M-up C-M-down C-M-right C-M-left
+                        C-S-up C-S-down C-S-right C-S-left
+                        M-S-up M-S-down M-S-right M-S-left
+                        C-M-S-up C-M-S-down C-M-S-right C-M-S-left))
+          (bind `[,key])))
+      (when (memq :navigation categories)
+        (dolist (key '( home C-home M-home S-home C-M-home C-S-home
+                        M-S-home C-M-S-home
+                        end C-end M-end S-end C-M-end C-S-end
+                        M-S-end C-M-S-end
+                        prior C-prior M-prior S-prior C-M-prior
+                        C-S-prior M-S-prior C-M-S-prior
+                        next C-next M-next S-next C-M-next C-S-next
+                        M-S-next C-M-S-next))
+          (bind `[,key])))
+      (when (memq :function categories)
+        (cl-loop
+         for i from 1 to 63
+         do (let ((key (intern (format "f%i" i))))
+              (bind `[,key]))))
+      (when (memq :mouse-click categories)
+        (dolist (key '(mouse-1 mouse-2 mouse-3))
+          (bind `[,key])))
+      (when (memq :mouse-modifier categories)
+        (dolist (key
+                 '( down-mouse-1 drag-mouse-1 down-mouse-2
+                    drag-mouse-2 down-mouse-3 drag-mouse-3
+                    C-down-mouse-1 C-drag-mouse-1 C-down-mouse-2
+                    C-drag-mouse-2 C-down-mouse-3 C-drag-mouse-3
+                    M-down-mouse-1 M-drag-mouse-1 M-down-mouse-2
+                    M-drag-mouse-2 M-down-mouse-3 M-drag-mouse-3
+                    S-down-mouse-1 S-drag-mouse-1 S-down-mouse-2
+                    S-drag-mouse-2 S-down-mouse-3 S-drag-mouse-3
+                    C-M-down-mouse-1 C-M-drag-mouse-1
+                    C-M-down-mouse-2 C-M-drag-mouse-2
+                    C-M-down-mouse-3 C-M-drag-mouse-3
+                    C-S-down-mouse-1 C-S-drag-mouse-1
+                    C-S-down-mouse-2 C-S-drag-mouse-2
+                    C-S-down-mouse-3 C-S-drag-mouse-3
+                    M-S-down-mouse-1 M-S-drag-mouse-1
+                    M-S-down-mouse-2 M-S-drag-mouse-2
+                    M-S-down-mouse-3 M-S-drag-mouse-3
+                    C-M-S-down-mouse-1 C-M-S-drag-mouse-1
+                    C-M-S-down-mouse-2 C-M-S-drag-mouse-2
+                    C-M-S-down-mouse-3 C-M-S-drag-mouse-3 mouse-1
+                    mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7
+                    mouse-8 mouse-9 mouse-10 mouse-11 C-mouse-1
+                    C-mouse-2 C-mouse-3 C-mouse-4 C-mouse-5
+                    C-mouse-6 C-mouse-7 C-mouse-8 C-mouse-9
+                    C-mouse-10 C-mouse-11 M-mouse-1 M-mouse-2
+                    M-mouse-3 M-mouse-4 M-mouse-5 M-mouse-6
+                    M-mouse-7 M-mouse-8 M-mouse-9 M-mouse-10
+                    M-mouse-11 S-mouse-1 S-mouse-2 S-mouse-3
+                    S-mouse-4 S-mouse-5 S-mouse-6 S-mouse-7
+                    S-mouse-8 S-mouse-9 S-mouse-10 S-mouse-11
+                    C-M-mouse-1 C-M-mouse-2 C-M-mouse-3 C-M-mouse-4
+                    C-M-mouse-5 C-M-mouse-6 C-M-mouse-7 C-M-mouse-8
+                    C-M-mouse-9 C-M-mouse-10 C-M-mouse-11
+                    C-S-mouse-1 C-S-mouse-2 C-S-mouse-3 C-S-mouse-4
+                    C-S-mouse-5 C-S-mouse-6 C-S-mouse-7 C-S-mouse-8
+                    C-S-mouse-9 C-S-mouse-10 C-S-mouse-11
+                    M-S-mouse-1 M-S-mouse-2 M-S-mouse-3 M-S-mouse-4
+                    M-S-mouse-5 M-S-mouse-6 M-S-mouse-7 M-S-mouse-8
+                    M-S-mouse-9 M-S-mouse-10 M-S-mouse-11
+                    C-M-S-mouse-1 C-M-S-mouse-2 C-M-S-mouse-3
+                    C-M-S-mouse-4 C-M-S-mouse-5 C-M-S-mouse-6
+                    C-M-S-mouse-7 C-M-S-mouse-8 C-M-S-mouse-9
+                    C-M-S-mouse-10 C-M-S-mouse-11 wheel-up
+                    wheel-down wheel-right wheel-left C-wheel-up
+                    C-wheel-down C-wheel-right C-wheel-left
+                    M-wheel-up M-wheel-down M-wheel-right
+                    M-wheel-left S-wheel-up S-wheel-down
+                    S-wheel-right S-wheel-left C-M-wheel-up
+                    C-M-wheel-down C-M-wheel-right C-M-wheel-left
+                    C-S-wheel-up C-S-wheel-down C-S-wheel-right
+                    C-S-wheel-left M-S-wheel-up M-S-wheel-down
+                    M-S-wheel-right M-S-wheel-left C-M-S-wheel-up
+                    C-M-S-wheel-down C-M-S-wheel-right
+                    C-M-S-wheel-left))
+          (bind `[,key])))
+      (when (memq :mouse-movement categories)
+        (bind [mouse-movement])))
+    map))
+
+(defun eat-term-name ()
+  "Return the value of `TERM' environment variable for Eat."
+  (if (stringp eat-term-name)
+      eat-term-name
+    (funcall eat-term-name)))
+
+(defun eat-term-get-suitable-term-name (&optional display)
+  "Return the most suitable value for `TERM' for DISPLAY.
+
+If the number of colors supported by display (as returned by
+`display-color-cells') is more than 256, return \"eat-truecolor\", if
+it is more than 8 but less than or equal to 256, return
+\"eat-256color\", if is more than 1 but less than or equal to 8,
+return \"eat-color\", otherwise return \"eat-mono\"."
+  (let ((colors (display-color-cells display)))
+    (cond ((> colors 256) "eat-truecolor")
+          ((> colors 8) "eat-256color")
+          ((> colors 1) "eat-color")
+          (t "eat-mono"))))
+
+(defun eat-term-filter-string (string)
+  "Filter Eat's special text properties from STRING."
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (while (not (eobp))
+      (eat--t-join-long-line))
+    (buffer-string)))
+
+
+;;;; Blink mode.
+
+(defvar eat--slow-blink-state nil
+  "Current state of slowly blinking text, t means inverse video.")
+
+(defvar eat--fast-blink-state nil
+  "Current state of rapidly blinking text, t means inverse video.")
+
+(defvar eat--slow-blink-remap nil
+  "Face remapping cookie of slowly blinking face.")
+
+(defvar eat--fast-blink-remap nil
+  "Face remapping cookie of rapidly blinking face.")
+
+(defvar eat--slow-blink-timer nil
+  "Timer for blinking slowly blinking text.")
+
+(defvar eat--fast-blink-timer nil
+  "Timer for blinking rapidly blinking text.")
+
+(defun eat--flip-slow-blink-state ()
+  "Flip the state of slowly blinking text."
+  (declare-function face-remap-add-relative "face-remap"
+                    (face &rest specs))
+  (declare-function face-remap-remove-relative "face-remap" (cookie))
+  (face-remap-remove-relative eat--slow-blink-remap)
+  (setq eat--slow-blink-remap
+        (face-remap-add-relative
+         'eat-slow-blink
+         `(:box nil :inverse-video ,(not eat--slow-blink-state))))
+  (setq eat--slow-blink-state (not eat--slow-blink-state)))
+
+(defun eat--flip-fast-blink-state ()
+  "Flip the state of rapidly blinking text."
+  (declare-function face-remap-add-relative "face-remap"
+                    (face &rest specs))
+  (declare-function face-remap-remove-relative "face-remap" (cookie))
+  (face-remap-remove-relative eat--fast-blink-remap)
+  (setq eat--fast-blink-remap
+        (face-remap-add-relative
+         'eat-fast-blink
+         `(:box nil :inverse-video ,(not eat--fast-blink-state))))
+  (setq eat--fast-blink-state (not eat--fast-blink-state)))
+
+(defun eat--blink-stop-timers ()
+  "Start blinking timers."
+  (when eat--slow-blink-timer
+    (cancel-timer eat--slow-blink-timer)
+    (setq eat--slow-blink-timer nil))
+  (when eat--fast-blink-timer
+    (cancel-timer eat--fast-blink-timer)
+    (setq eat--fast-blink-timer nil)))
+
+(defun eat--blink-start-timers ()
+  "Start blinking timers."
+  (eat--blink-stop-timers)
+  (setq eat--slow-blink-timer
+        (run-with-timer t (/ (float eat-slow-blink-frequency))
+                        #'eat--flip-slow-blink-state))
+  (setq eat--fast-blink-timer
+        (run-with-timer t (/ (float eat-fast-blink-frequency))
+                        #'eat--flip-fast-blink-state)))
+
+(define-minor-mode eat-blink-mode
+  "Toggle blinking of text with blink attribute."
+  :lighter " Eat-Blink"
+  (declare-function face-remap-add-relative "face-remap"
+                    (face &rest specs))
+  (cond
+   (eat-blink-mode
+    (setq eat-blink-mode nil)
+    (require 'face-remap)
+    (setq eat-blink-mode t)
+    (make-local-variable 'eat--slow-blink-state)
+    (make-local-variable 'eat--fast-blink-state)
+    (make-local-variable 'eat--slow-blink-remap)
+    (make-local-variable 'eat--fast-blink-remap)
+    (make-local-variable 'eat--slow-blink-timer)
+    (make-local-variable 'eat--fast-blink-timer)
+    (setq eat--slow-blink-state nil)
+    (setq eat--fast-blink-state nil)
+    (setq eat--slow-blink-remap
+          (face-remap-add-relative 'eat-term-slow-blink '(:box nil)))
+    (setq eat--fast-blink-remap
+          (face-remap-add-relative 'eat-term-fast-blink '(:box nil)))
+    (add-hook 'pre-command-hook #'eat--blink-stop-timers nil t)
+    (add-hook 'post-command-hook #'eat--blink-start-timers nil t))
+   (t
+    (eat--blink-stop-timers)
+    (face-remap-remove-relative eat--slow-blink-remap)
+    (face-remap-remove-relative eat--fast-blink-remap)
+    (remove-hook 'pre-command-hook #'eat--blink-stop-timers t)
+    (remove-hook 'post-command-hook #'eat--blink-start-timers t)
+    (kill-local-variable 'eat--slow-blink-state)
+    (kill-local-variable 'eat--fast-blink-state)
+    (kill-local-variable 'eat--slow-blink-remap)
+    (kill-local-variable 'eat--fast-blink-remap)
+    (kill-local-variable 'eat--slow-blink-timer)
+    (kill-local-variable 'eat--fast-blink-timer))))
+
+
+;;;; Buffer-local Cursor Blinking.
+
+(defvar eat--cursor-blink-type nil
+  "Type of blinking cursor.")
+
+(defvar eat--cursor-blink-state nil
+  "Current state of slowly blinking text, non-nil means on.")
+
+(defvar eat--cursor-blink-timer nil
+  "Timer for blinking slowly blinking text.")
+
+(defvar eat--cursor-blink-mode)
+
+(defun eat--flip-cursor-blink-state ()
+  "Flip the state of slowly blinking text."
+  (when (and eat--cursor-blink-mode
+             (display-graphic-p))
+    (setq-local cursor-type (if eat--cursor-blink-state
+                                (caddr eat--cursor-blink-type)
+                              (car eat--cursor-blink-type)))
+    (setq eat--cursor-blink-state (not eat--cursor-blink-state))
+    ;; REVIEW: This is expensive, and some causes flickering.  Any
+    ;; better way?
+    (when-let ((window (get-buffer-window nil 'visible)))
+      (redraw-frame (window-frame window)))))
+
+(defun eat--cursor-blink-stop-timers ()
+  "Stop blinking timers."
+  (unless eat--cursor-blink-state
+    (eat--flip-cursor-blink-state))
+  (when eat--cursor-blink-timer
+    (cancel-timer eat--cursor-blink-timer)
+    (setq eat--cursor-blink-timer nil)))
+
+(defun eat--cursor-blink-start-timers ()
+  "Start blinking timers."
+  (eat--cursor-blink-stop-timers)
+  (setq eat--cursor-blink-timer
+        (run-with-timer t (/ (float (cadr eat--cursor-blink-type)))
+                        #'eat--flip-cursor-blink-state)))
+
+(define-minor-mode eat--cursor-blink-mode
+  "Toggle blinking of cursor."
+  :interactive nil
+  (cond
+   (eat--cursor-blink-mode
+    (make-local-variable 'eat--cursor-blink-state)
+    (make-local-variable 'eat--cursor-blink-timer)
+    (setq eat--cursor-blink-state nil)
+    (setq eat--cursor-blink-timer nil)
+    (add-hook 'pre-command-hook #'eat--cursor-blink-stop-timers nil t)
+    (add-hook 'post-command-hook #'eat--cursor-blink-start-timers
+              nil t)
+    (when (current-idle-time)
+      (eat--cursor-blink-start-timers)))
+   (t
+    (eat--cursor-blink-stop-timers)
+    (remove-hook 'pre-command-hook #'eat--cursor-blink-stop-timers t)
+    (remove-hook 'post-command-hook #'eat--cursor-blink-start-timers
+                 t)
+    (kill-local-variable 'eat--cursor-blink-state)
+    (kill-local-variable 'eat--cursor-blink-timer))))
+
+
+;;;; User Interface.
+
+(defvar eat--terminal nil
+  "The terminal object.")
+
+(defvar eat--synchronize-scroll-function nil
+  "Function to synchronize scrolling between terminal and window.")
+
+(defun eat-reset ()
+  "Perform a terminal reset."
+  (interactive)
+  (when eat--terminal
+    (let ((inhibit-read-only t))
+      (eat-term-reset eat--terminal)
+      (eat-term-redisplay eat--terminal))))
+
+(defun eat--set-cursor (_ state)
+  "Set cursor type according to STATE.
+
+  STATE can be one of the following:
+
+  `:default'            Default cursor.
+  `:invisible'          Invisible cursor.
+  `:very-visible'       Very visible cursor.  Can also be implemented
+                        as blinking cursor.
+  Any other value     Default cursor."
+  (setq-local eat--cursor-blink-type
+              (pcase state
+                (:invisible eat-invisible-cursor-type)
+                (:very-visible eat-very-visible-cursor-type)
+                (_ eat-default-cursor-type))) ; `:default'
+  (setq-local cursor-type (car eat--cursor-blink-type))
+  (eat--cursor-blink-mode (if (cadr eat--cursor-blink-type) +1 -1)))
+
+
+;;;;; Input.
+
+(defvar eat--mouse-grabbing-type nil
+  "Current mouse grabbing type/mode.")
+
+(defvar eat--mouse-pressed-buttons nil
+  "Mouse buttons currently pressed.")
+
+(defvar eat--mouse-last-position nil
+  "Last position of mouse, nil when not dragging.")
+
+(defvar eat--mouse-drag-transient-map-exit nil
+  "Function to exit mouse dragging transient map.")
+
+(defun eat-self-input (n &optional e)
+  "Send E as input N times.
+
+N defaults to 1 and E defaults to `last-command-event' and should be a
+event."
+  (interactive
+   (list (prefix-numeric-value current-prefix-arg)
+         (if (and (> (length (this-command-keys)) 1)
+                  (eq (aref (this-command-keys)
+                            (- (length (this-command-keys)) 2))
+                      meta-prefix-char))
+             ;; HACK: Capture meta modifier (ESC prefix) in terminal.
+             (cond
+              ((eq last-command-event meta-prefix-char)
+               last-command-event)
+              ((characterp last-command-event)
+               (aref
+                (kbd (format "M-%c" last-command-event))
+                0))
+              ((symbolp last-command-event)
+               (aref
+                (kbd (format "M-<%S>" last-command-event))
+                0))
+              (t
+               last-command-event))
+           last-command-event)))
+  (when (memq (event-basic-type e)
+              '( mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6
+                 mouse-7 mouse-8 mouse-9 mouse-10 mouse-11))
+    (select-window (posn-window (event-start e))))
+  (when eat--terminal
+    (unless (mouse-movement-p e)
+      (funcall eat--synchronize-scroll-function))
+    (if (memq (event-basic-type e)
+              '( mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6
+                 mouse-7 mouse-8 mouse-9 mouse-10 mouse-11
+                 mouse-movement))
+        (let ((disp-begin-posn
+               (posn-at-point
+                (eat-term-display-beginning eat--terminal)))
+              (e (if (or (not eat--mouse-last-position)
+                         (eq (posn-window
+                              (if (memq 'drag (event-modifiers e))
+                                  (event-end e)
+                                (event-start e)))
+                             (posn-window eat--mouse-last-position)))
+                     e
+                   (pcase e
+                     (`(,type ,_)
+                      `(,type ,eat--mouse-last-position))
+                     (`(,type ,start ,_)
+                      `(,type ,start ,eat--mouse-last-position))
+                     (ev ev)))))
+          (if (not (mouse-movement-p e))
+              (eat-term-input-event eat--terminal n e disp-begin-posn)
+            (if (not eat--mouse-pressed-buttons)
+                (when (eq eat--mouse-grabbing-type :all)
+                  (eat-term-input-event eat--terminal n e
+                                        disp-begin-posn))
+              (when (memq eat--mouse-grabbing-type '(:all :drag))
+                (eat-term-input-event eat--terminal n e
+                                      disp-begin-posn))
+              (setq eat--mouse-last-position (event-start e))))
+          (when (memq (event-basic-type e) '(mouse-1 mouse-2 mouse-3))
+            (when (or (memq 'click (event-modifiers e))
+                      (memq 'drag (event-modifiers e)))
+              (setq eat--mouse-pressed-buttons
+                    (delq (event-basic-type e)
+                          eat--mouse-pressed-buttons))
+              (unless eat--mouse-pressed-buttons
+                (setq eat--mouse-last-position nil)
+                (when eat--mouse-drag-transient-map-exit
+                  (funcall eat--mouse-drag-transient-map-exit)
+                  (setq eat--mouse-drag-transient-map-exit nil))))
+            (when (memq 'down (event-modifiers e))
+              (push (event-basic-type e) eat--mouse-pressed-buttons)
+              (setq eat--mouse-last-position (event-start e))
+              (unless eat--mouse-drag-transient-map-exit
+                (let ((old-track-mouse track-mouse)
+                      (buffer (current-buffer)))
+                  (setq track-mouse 'dragging)
+                  (setq eat--mouse-drag-transient-map-exit
+                        (set-transient-map
+                         (let ((map (eat-term-make-keymap
+                                     #'eat-self-input
+                                     '(:mouse-modifier
+                                       :mouse-movement)
+                                     nil)))
+                           ;; Some of the events will of course end up
+                           ;; looked up with a mode-line, header-line
+                           ;; or vertical-line prefix ...
+                           (define-key map [mode-line] map)
+                           (define-key map [header-line] map)
+                           (define-key map [tab-line] map)
+                           (define-key map [vertical-line] map)
+                           ;; ... and some maybe even with a right- or
+                           ;; bottom-divider prefix.
+                           (define-key map [right-divider] map)
+                           (define-key map [bottom-divider] map))
+                         #'always
+                         (lambda ()
+                           (with-current-buffer buffer
+                             (setq track-mouse
+                                   old-track-mouse))))))))))
+      (eat-term-input-event eat--terminal n e))))
+
+(defun eat-quoted-input ()
+  "Read a char and send it as INPUT."
+  (declare (interactive-only "Use `eat-self-input' instead."))
+  (interactive)
+  ;; HACK: Quick hack to allow inputting `C-g'.  Any better way to do
+  ;; this?
+  (eat-self-input 1 (let ((inhibit-quit t)
+                          (quit-flag nil))
+                      (read-event))))
+
+(defun eat-yank (&optional arg)
+  "Same as `yank', but for Eat.
+
+ARG is passed to `yank', which see."
+  (interactive "*P")
+  (when eat--terminal
+    (funcall eat--synchronize-scroll-function)
+    (cl-letf* ((inhibit-read-only t)
+               (insert-for-yank (symbol-function #'insert-for-yank))
+               ((symbol-function #'insert-for-yank)
+                (lambda (&rest args)
+                  (cl-letf (((symbol-function #'insert)
+                             (lambda (&rest args)
+                               (eat-send-string-as-yank
+                                eat--terminal
+                                (mapconcat (lambda (arg)
+                                             (if (stringp arg)
+                                                 arg
+                                               (string arg)))
+                                           args)))))
+                    (apply insert-for-yank args)))))
+      (yank arg))))
+
+(defun eat-yank-pop (&optional arg)
+  "Same as `yank-pop', but for Eat.
+
+ARG is passed to `yank-pop', which see."
+  (interactive "p")
+  (when eat--terminal
+    (funcall eat--synchronize-scroll-function)
+    (cl-letf* ((inhibit-read-only t)
+               (insert-for-yank (symbol-function #'insert-for-yank))
+               ((symbol-function #'insert-for-yank)
+                (lambda (&rest args)
+                  (cl-letf (((symbol-function #'insert)
+                             (lambda (&rest args)
+                               (eat-send-string-as-yank
+                                eat--terminal
+                                (mapconcat (lambda (arg)
+                                             (if (stringp arg)
+                                                 arg
+                                               (string arg)))
+                                           args)))))
+                    (apply insert-for-yank args)))))
+      (yank-pop arg))))
+
+;; When changing these keymaps, be sure to update the manual, README
+;; and commentary.
+(defvar eat-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [?\C-c ?\M-d] #'eat-char-mode)
+    (define-key map [?\C-c ?\C-j] #'eat-semi-char-mode)
+    (define-key map [?\C-c ?\C-k] #'eat-kill-process)
+    map)
+  "Keymap for Eat mode.")
+
+(defvar eat-semi-char-mode-map
+  (let ((map (eat-term-make-keymap
+              #'eat-self-input
+              '(:ascii :arrow :navigation)
+              '( [?\C-\\] [?\C-q] [?\C-c] [?\C-x] [?\C-g] [?\C-h]
+                 [?\e ?\C-c] [?\C-u] [?\C-q] [?\e ?x] [?\e ?:]
+                 [?\e ?!] [?\e ?&] [?\C-y] [?\e ?y]))))
+    (define-key map [?\C-q] #'eat-quoted-input)
+    (define-key map [?\C-y] #'eat-yank)
+    (define-key map [?\M-y] #'eat-yank-pop)
+    (define-key map [?\C-c ?\C-c] #'eat-self-input)
+    (define-key map [?\C-c ?\C-e] #'eat-emacs-mode)
+    map)
+  "Keymap for Eat semi-char mode.")
+
+(defvar eat-char-mode-map
+  (let ((map (eat-term-make-keymap
+              #'eat-self-input
+              '(:ascii :arrow :navigation :function)
+              '([?\e ?\C-m]))))
+    (define-key map [?\C-\M-m] #'eat-semi-char-mode)
+    map)
+  "Keymap for Eat char mode.")
+
+(defvar eat--mouse-click-mode-map
+  (eat-term-make-keymap #'eat-self-input '(:mouse-click) nil)
+  "Keymap for `eat--mouse-click-mode'.")
+
+(defvar eat--mouse-modifier-click-mode-map
+  (eat-term-make-keymap #'eat-self-input '(:mouse-modifier) nil)
+  "Keymap for `eat--mouse-modifier-click-mode'.")
+
+(defvar eat--mouse-movement-mode-map
+  (eat-term-make-keymap #'eat-self-input '(:mouse-movement) nil)
+  "Keymap for `eat--mouse-movement-mode'.")
+
+(define-minor-mode eat--semi-char-mode
+  "Minor mode for semi-char mode keymap."
+  :interactive nil
+  :keymap eat-semi-char-mode-map)
+
+(define-minor-mode eat--char-mode
+  "Minor mode for char mode keymap."
+  :interactive nil
+  :keymap eat-char-mode-map)
+
+(define-minor-mode eat--mouse-click-mode
+  "Minor mode for mouse click keymap."
+  :interactive nil)
+
+(define-minor-mode eat--mouse-modifier-click-mode
+  "Minor mode for mouse click with modifiers keymap."
+  :interactive nil)
+
+(define-minor-mode eat--mouse-movement-mode
+  "Minor mode for mouse movement keymap."
+  :interactive nil)
+
+(defun eat-emacs-mode ()
+  "Switch to Emacs keybindings mode."
+  (interactive)
+  (eat--semi-char-mode -1)
+  (eat--char-mode -1)
+  (setq buffer-read-only t)
+  (eat--grab-mouse nil eat--mouse-grabbing-type)
+  (force-mode-line-update))
+
+(defun eat-semi-char-mode ()
+  "Switch to semi-char mode."
+  (interactive)
+  (if (not eat--terminal)
+      (error "Process not running")
+    (setq buffer-read-only nil)
+    (eat--char-mode -1)
+    (eat--semi-char-mode +1)
+    (eat--grab-mouse nil eat--mouse-grabbing-type)
+    (force-mode-line-update)))
+
+(defun eat-char-mode ()
+  "Switch to char mode."
+  (interactive)
+  (if (not eat--terminal)
+      (error "Process not running")
+    (setq buffer-read-only nil)
+    (eat--semi-char-mode -1)
+    (eat--char-mode +1)
+    (eat--grab-mouse nil eat--mouse-grabbing-type)
+    (force-mode-line-update)))
+
+(defvar eat--eshell-semi-char-mode)
+(defvar eat--eshell-char-mode)
+
+(defun eat--grab-mouse (_ mode)
+  "Grab mouse.
+
+MODE should one of:
+
+  nil                 Disable mouse.
+  `:click'              Pass `mouse-1', `mouse-2', and `mouse-3'
+                        clicks.
+  `:modifier-click'     Pass all mouse clicks, including control,
+                        meta and shift modifiers.
+  `:drag'               All of :modifier-click, plus dragging
+                        (moving mouse while pressed) information.
+  `:all'                Pass all mouse events, including movement.
+  Any other value     Disable mouse."
+  (setq eat--mouse-grabbing-type mode)
+  (pcase (and eat-enable-mouse
+              (or eat--semi-char-mode
+                  eat--char-mode
+                  eat--eshell-semi-char-mode
+                  eat--eshell-char-mode)
+              mode)
+    (:all
+     (setq track-mouse t)
+     (eat--mouse-click-mode -1)
+     (eat--mouse-modifier-click-mode +1)
+     (eat--mouse-movement-mode +1))
+    ((or :modifier-click :drag)
+     (setq track-mouse nil)
+     (eat--mouse-click-mode -1)
+     (eat--mouse-movement-mode -1)
+     (eat--mouse-modifier-click-mode +1))
+    (:click
+     (setq track-mouse nil)
+     (eat--mouse-modifier-click-mode -1)
+     (eat--mouse-movement-mode -1)
+     (eat--mouse-click-mode +1))
+    (_
+     (setq track-mouse nil)
+     (eat--mouse-click-mode -1)
+     (eat--mouse-modifier-click-mode -1)
+     (eat--mouse-movement-mode -1))))
+
+(defun eat--manipulate-kill-ring (_ selection data)
+  "Manipulate `kill-ring'.
+
+SELECTION can be one of `:clipboard', `:primary', `:secondary',
+`:select'.  When DATA is a string, set the selection to that string,
+when DATA is nil, unset the selection, and when DATA is t, return the
+selection, or nil if none."
+  (let ((inhibit-eol-conversion t)
+        (select-enable-clipboard (eq selection :clipboard))
+        (select-enable-primary (eq selection :primary)))
+    (pcase data
+      ('t
+       (when eat-enable-yank-to-terminal
+         (ignore-error error
+           (current-kill 0 'do-not-move))))
+      ((and (pred stringp)
+            str)
+       (when eat-enable-kill-from-terminal
+         (kill-new str))))))
+
+(defun eat--bell (_)
+  "Ring the bell."
+  (beep t))
+
+
+;;;;; Major Mode.
+
+(defun eat--synchronize-scroll ()
+  "Synchronize scrolling and point between terminal and window."
+  (when-let ((window (get-buffer-window (current-buffer))))
+    (set-window-start
+     window (eat-term-display-beginning eat--terminal)))
+  (goto-char (eat-term-display-cursor eat--terminal)))
+
+(defun eat--setup-glyphless-chars ()
+  "Setup the display of glyphless characters."
+  (setq-local glyphless-char-display
+              (copy-sequence (default-value 'glyphless-char-display)))
+  (set-char-table-extra-slot
+   glyphless-char-display 0
+   (if (display-graphic-p) 'empty-box 'thin-space)))
+
+(defun eat--filter-buffer-substring (begin end &optional delete)
+  "Filter buffer substring from BEGIN to END and return that.
+
+When DELETE is given and non-nil, delete the text between BEGIN and
+END if it's safe to do so."
+  (let ((str (eat-term-filter-string (buffer-substring begin end))))
+    (when (and delete
+               (or (not eat--terminal)
+                   (and (<= (eat-term-end eat--terminal) begin)
+                        (<= (eat-term-end eat--terminal) end))
+                   (and (<= begin (eat-term-beginning eat--terminal))
+                        (<= end (eat-term-beginning eat--terminal)))))
+      (delete-region begin end))
+    str))
+
+(define-derived-mode eat-mode fundamental-mode "Eat"
+  "Major mode for Eat."
+  :group 'eat-ui
+  (make-local-variable 'buffer-read-only)
+  (make-local-variable 'buffer-undo-list)
+  (make-local-variable 'filter-buffer-substring-function)
+  (make-local-variable 'mode-line-process)
+  (make-local-variable 'mode-line-buffer-identification)
+  (make-local-variable 'glyphless-char-display)
+  (make-local-variable 'cursor-type)
+  (make-local-variable 'track-mouse)
+  (make-local-variable 'eat--terminal)
+  (make-local-variable 'eat--process)
+  (make-local-variable 'eat--synchronize-scroll-function)
+  (make-local-variable 'eat--mouse-grabbing-type)
+  (make-local-variable 'eat--pending-output-chunks)
+  (make-local-variable 'eat--output-queue-first-chunk-time)
+  (make-local-variable 'eat--process-output-queue-timer)
+  ;; This is intended; input methods don't work on read-only buffers.
+  (setq buffer-read-only nil)
+  (setq buffer-undo-list t)
+  (setq eat--synchronize-scroll-function #'eat--synchronize-scroll)
+  (setq eat--mouse-grabbing-type nil)
+  (setq filter-buffer-substring-function
+        #'eat--filter-buffer-substring)
+  (setq mode-line-process
+        '(""
+          (:eval
+           (when eat--process
+             (cond
+              (eat--semi-char-mode
+               `("["
+                 (:propertize
+                  "semi-char"
+                  help-echo
+                  ,(concat "mouse-1: Switch to char mode, "
+                           "mouse-3: Switch to emacs mode")
+                  mouse-face mode-line-highlight
+                  local-map
+                  (keymap
+                   (mode-line
+                    . (keymap
+                       (down-mouse-1 . eat-char-mode)
+                       (down-mouse-3 . eat-emacs-mode)))))
+                 "]"))
+              (eat--char-mode
+               '("["
+                 (:propertize
+                  "char"
+                  help-echo
+                  ,(concat "mouse-1: Switch to semi-char mode, "
+                           "mouse-3: Switch to emacs mode")
+                  mouse-face mode-line-highlight
+                  local-map
+                  (keymap
+                   (mode-line
+                    . (keymap
+                       (down-mouse-1 . eat-semi-char-mode)
+                       (down-mouse-3 . eat-emacs-mode)))))
+                 "]"))
+              (t
+               `("["
+                 (:propertize
+                  "emacs"
+                  help-echo
+                  ,(concat "mouse-1: Switch to semi char mode, "
+                           "mouse-3: Switch to char mode")
+                  mouse-face mode-line-highlight
+                  local-map
+                  (keymap
+                   (mode-line
+                    . (keymap
+                       (down-mouse-1 . eat-semi-char-mode)
+                       (down-mouse-3 . eat-char-mode)))))
+                 "]")))))
+          ":%s"))
+  (setq mode-line-buffer-identification
+        `(12 (""
+              ,(nconc
+                (propertized-buffer-identification "%b")
+                '(" "
+                  (:propertize
+                   (:eval
+                    (when (and eat--terminal
+                               (not (string-empty-p (eat-term-title
+                                                     eat--terminal))))
+                      (format "(%s)"  (eat-term-title
+                                       eat--terminal))))
+                   help-echo "Title"))))))
+  (eat-emacs-mode)
+  ;; Make sure glyphless character don't display a huge box glyph,
+  ;; that would break the display.
+  (eat--setup-glyphless-chars)
+  (when eat-enable-blinking-text
+    (eat-blink-mode +1)))
+
+
+;;;;; Process Handling.
+
+(defvar eat--process nil
+  "The running process.")
+
+(defvar eat--pending-output-chunks nil
+  "The list of pending output chunks.
+
+The output chunks are pushed, so last output appears first.")
+
+(defvar eat--output-queue-first-chunk-time nil
+  "Time when the first chunk in the current output queue was pushed.")
+
+(defvar eat--process-output-queue-timer nil
+  "Timer to process output queue.")
+
+(defun eat-kill-process ()
+  "Kill Eat process in current buffer."
+  (interactive)
+  (when eat--process
+    (kill-process eat--process)))
+
+(defun eat--send-string (process string)
+  "Send to PROCESS the contents of STRING as input.
+
+This is equivalent to `process-send-string', except that long input
+strings are broken up into chunks of size `eat-input-chunk-size'.
+Processes are given a chance to output between chunks.  This can help
+prevent processes from hanging when you send them long inputs on some
+OS's."
+  (let ((i 0)
+        (j eat-input-chunk-size)
+        (l (length string)))
+    (while (< i l)
+      (process-send-string process (substring string i (min j l)))
+      (accept-process-output)
+      (cl-incf i eat-input-chunk-size)
+      (cl-incf j eat-input-chunk-size))))
+
+(defun eat--send-input (_ input)
+  "Send INPUT to subprocess."
+  (when eat--process
+    (eat--send-string eat--process input)))
+
+(defun eat--process-output-queue (buffer)
+  "Process the output queue on BUFFER."
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (let ((inhibit-quit t)            ; Don't disturb!
+            (inhibit-read-only t)
+            (inhibit-modification-hooks t)
+            (synchronize-scroll
+             (or (= (eat-term-display-cursor eat--terminal) (point))
+                 eat--char-mode)))
+        (when eat--process-output-queue-timer
+          (cancel-timer eat--process-output-queue-timer))
+        (setq eat--output-queue-first-chunk-time nil)
+        (let ((queue eat--pending-output-chunks))
+          (setq eat--pending-output-chunks nil)
+          (dolist (output (nreverse queue))
+            (eat-term-process-output eat--terminal output)))
+        (eat-term-redisplay eat--terminal)
+        ;; Truncate output of previous dead processes.
+        (when (and eat-term-scrollback-size
+                   (< eat-term-scrollback-size
+                      (- (point) (point-min))))
+          (delete-region
+           (point-min)
+           (max (point-min)
+                (- (eat-term-display-beginning eat--terminal)
+                   eat-term-scrollback-size))))
+        (when synchronize-scroll
+          (funcall eat--synchronize-scroll-function))))))
+
+(defun eat--filter (process output)
+  "Handle OUTPUT from PROCESS."
+  (when (buffer-live-p (process-buffer process))
+    (with-current-buffer (process-buffer process)
+      (when eat--process-output-queue-timer
+        (cancel-timer eat--process-output-queue-timer))
+      (unless eat--output-queue-first-chunk-time
+        (setq eat--output-queue-first-chunk-time (current-time)))
+      (push output eat--pending-output-chunks)
+      (let ((time-left
+             (- eat-maximum-latency
+                (float-time
+                 (time-subtract
+                  nil eat--output-queue-first-chunk-time)))))
+        (if (<= time-left 0)
+            (eat--process-output-queue (current-buffer))
+          (setq eat--process-output-queue-timer
+                (run-with-timer
+                 (min time-left eat-minimum-latency) nil
+                 #'eat--process-output-queue (current-buffer))))))))
+
+(defun eat--sentinel (process message)
+  "Sentinel for Eat buffers.
+
+PROCESS is the process and MESSAGE is the description of what happened
+to it."
+  (let ((buffer (process-buffer process)))
+    (when (memq (process-status process) '(signal exit))
+      (if (buffer-live-p buffer)
+          (if eat-kill-buffer-on-exit
+              (kill-buffer buffer)
+            (with-current-buffer buffer
+              (let ((inhibit-read-only t))
+                (eat--process-output-queue (current-buffer))
+                (eat-emacs-mode)
+                (setq eat--process nil)
+                (delete-process process)
+                (eat-term-delete eat--terminal)
+                (setq eat--terminal nil)
+                (eat--set-cursor nil :default)
+                (eat--grab-mouse nil nil)
+                (goto-char (point-max))
+                (insert "\nProcess " (process-name process) " "
+                        message)
+                (setq buffer-read-only nil))))
+        (set-process-buffer process nil)))))
+
+(defun eat--adjust-process-window-size (process windows)
+  "Resize process window and terminal.  Return new dimensions.
+
+PROCESS is the process whose window to resize, and WINDOWS is the list
+of window displaying PROCESS's buffer."
+  (let* ((size (funcall window-adjust-process-window-size-function
+                        process windows)))
+    (when size
+      (let ((width (max (car size) 1))
+            (height (max (cdr size) 1))
+            (inhibit-read-only t)
+            (synchronize-scroll
+             (and (<= (eat-term-display-beginning eat--terminal)
+                      (point))
+                  (or (< (point) (eat-term-end eat--terminal))
+                      (= (point) (eat-term-end eat--terminal)
+                         (point-max))))))
+        (eat-term-resize eat--terminal width height)
+        (eat-term-redisplay eat--terminal)
+        (when synchronize-scroll
+          (funcall eat--synchronize-scroll-function))))
+    size))
+
+;; Adapted from Term.
+(defun eat-exec (buffer name command startfile switches)
+  "Start up a process in BUFFER for Eat mode.
+
+Run COMMAND with SWITCHES.  Set NAME as the name of the process.
+Blast any old process running in the buffer.  Don't set the buffer
+mode.  You can use this to cheaply run a series of processes in the
+same Eat buffer.  The hook `eat-exec-hook' is run after each exec."
+  (with-current-buffer buffer
+    (let ((inhibit-read-only t))
+      (when eat--process
+        (let ((eat-kill-buffer-on-exit nil))
+          (delete-process eat--process)))
+      ;; Ensure final newline.
+      (goto-char (point-max))
+      (unless (or (= (point-min) (point-max))
+                  (= (char-before (point-max)) ?\n))
+        (insert ?\n))
+      (unless (= (point-min) (point-max))
+        (insert "\n\n"))
+      (setq eat--terminal (eat-term-make buffer (point)))
+      (eat-semi-char-mode)
+      (when-let ((window (get-buffer-window nil t)))
+        (with-selected-window window
+          (eat-term-resize eat--terminal (window-max-chars-per-line)
+                           (window-text-height))))
+      (setf (eat-term-input-function eat--terminal) #'eat--send-input)
+      (setf (eat-term-set-cursor-function eat--terminal)
+            #'eat--set-cursor)
+      (setf (eat-term-grab-mouse-function eat--terminal)
+            #'eat--grab-mouse)
+      (setf (eat-term-manipulate-selection-function eat--terminal)
+            #'eat--manipulate-kill-ring)
+      (setf (eat-term-ring-bell-function eat--terminal) #'eat--bell)
+      ;; Crank up a new process.
+      (let* ((size (eat-term-size eat--terminal))
+             (process-environment
+              (nconc
+               (list
+                (concat "TERM=" (eat-term-name))
+                (concat "TERMINFO=" eat-term-terminfo-directory)
+                (concat "INSIDE_EMACS=" eat-term-inside-emacs))
+               process-environment))
+             (process-connection-type t)
+             ;; We should suppress conversion of end-of-line format.
+             (inhibit-eol-conversion t)
+             (process
+              (make-process
+               :name name
+               :buffer buffer
+               :command `("/usr/bin/env" "sh" "-c"
+                          ,(format "stty -nl echo rows %d columns \
+%d sane 2>%s ; if [ $1 = .. ]; then shift; fi; exec \"$@\""
+                                   (cdr size) (car size)
+                                   null-device)
+                          ".."
+                          ,command ,@switches)
+               :filter #'eat--filter
+               :sentinel #'eat--sentinel
+               :file-handler t)))
+        (process-put process 'adjust-window-size-function
+                     #'eat--adjust-process-window-size)
+        ;; Jump to the end, and set the process mark.
+        (goto-char (point-max))
+        (set-marker (process-mark process) (point))
+        (setq eat--process process)
+        ;; Feed it the startfile.
+        (when startfile
+          ;;This is guaranteed to wait long enough
+          ;;but has bad results if the shell does not prompt at all
+          ;;         (while (= size (buffer-size))
+          ;;           (sleep-for 1))
+          ;;I hope 1 second is enough!
+          (sleep-for 1)
+          (goto-char (point-max))
+          (insert-file-contents startfile)
+          (process-send-string
+           process (delete-and-extract-region (point) (point-max)))))
+      (eat-term-redisplay eat--terminal)
+      (run-hooks 'eat-exec-hook)
+      buffer)))
+
+
+;;;;; Entry Points.
+
+(defun eat-make (name program &optional startfile &rest switches)
+  "Make a Eat process NAME in a buffer, running PROGRAM.
+
+The name of the buffer is made by surrounding NAME with `*'s.  If
+there is already a running process in that buffer, it is not
+restarted.  Optional third arg STARTFILE is the name of a file to send
+the contents of to the process.  SWITCHES are the arguments to
+PROGRAM."
+  (let ((buffer (get-buffer-create (concat "*" name "*"))))
+    ;; If no process, or nuked process, crank up a new one and put
+    ;; buffer in Eat mode.  Otherwise, leave buffer and existing
+    ;; process alone.
+    (when (not (let ((proc (get-buffer-process buffer)))
+                 (and proc (memq (process-status proc)
+                                 '(run stop open listen connect)))))
+      (with-current-buffer buffer
+        (eat-mode))
+      (eat-exec buffer name program startfile switches))
+    buffer))
+
+;;;###autoload
+(defun eat (&optional program arg)
+  "Start a new Eat terminal emulator in a buffer.
+
+Start a new Eat session, or switch to an already active session.
+Return the buffer selected (or created).
+
+With a non-numeric prefix ARG, create a new session.
+
+With a numeric prefix ARG (like \\[universal-argument] 42 \\[eshell]),
+switch to the session with that number, or create it if it doesn't
+already exist.
+
+PROGRAM can be a shell command."
+  (interactive (list (read-shell-command "Run program: "
+                                         (or explicit-shell-file-name
+                                             (getenv "ESHELL")
+                                             shell-file-name))
+                     current-prefix-arg))
+  (let ((program (or program (or explicit-shell-file-name
+                                 (getenv "ESHELL")
+                                 shell-file-name)))
+        (buffer
+         (cond
+          ((numberp arg)
+          (get-buffer-create (format "%s<%d>" eat-buffer-name arg)))
+         (arg
+          (generate-new-buffer eat-buffer-name))
+         (t
+          (get-buffer-create eat-buffer-name)))))
+    (with-current-buffer buffer
+      (unless (eq major-mode #'eat-mode)
+        (eat-mode))
+      (pop-to-buffer-same-window buffer)
+      (unless eat--process
+        (eat-exec buffer "eat" "/usr/bin/env" nil
+                  `("sh" "-c" ,program)))
+      buffer)))
+
+
+;;;; Eshell integration.
+
+;;;;; Input.
+
+;; When changing these keymaps, be sure to update the manual, README
+;; and commentary.
+(defvar eat-eshell-emacs-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [?\C-c ?\C-j] #'eat-eshell-semi-char-mode)
+    (define-key map [remap eshell-toggle-direct-send] ; C-c M-d
+                #'eat-eshell-char-mode)
+    map)
+  "Keymap for Eat Eshell when no process is running.")
+
+(defvar eat-eshell-semi-char-mode-map
+  (let ((map (eat-term-make-keymap
+              #'eat-self-input
+              '(:ascii :arrow :navigation)
+              '( [?\C-\\] [?\C-q] [?\C-c] [?\C-x] [?\C-g] [?\C-h]
+                 [?\e ?\C-c] [?\C-u] [?\C-q] [?\e ?x] [?\e ?:]
+                 [?\e ?!] [?\e ?&] [?\C-y] [?\e ?y]))))
+    (define-key map [?\C-q] #'eat-quoted-input)
+    (define-key map [?\C-y] #'eat-yank)
+    (define-key map [?\M-y] #'eat-yank-pop)
+    (define-key map [?\C-c ?\C-e] #'eat-eshell-emacs-mode)
+    map)
+  "Keymap for Eat Eshell semi-char mode.")
+
+(defvar eat-eshell-char-mode-map
+  (let ((map (eat-term-make-keymap
+              #'eat-self-input
+              '(:ascii :arrow :navigation :function)
+              '([?\e ?\C-m]))))
+    (define-key map [?\C-\M-m] #'eat-eshell-semi-char-mode)
+    map)
+  "Keymap for Eat Eshell char mode.")
+
+(define-minor-mode eat--eshell-semi-char-mode
+  "Minor mode for semi-char mode keymap."
+  :interactive nil
+  :keymap eat-eshell-semi-char-mode-map
+  ;; HACK: Some keys like `C-c' are overriden by other keymaps
+  ;; (possibly by the keymaps of other minor modes), so we also put
+  ;; the keymap to `minor-mode-overriding-map-alist' to make Emacs
+  ;; prioritize us.
+  (setq minor-mode-overriding-map-alist
+        (delete (cons #'eat--eshell-semi-char-mode
+                      eat-eshell-semi-char-mode-map)
+                minor-mode-overriding-map-alist))
+  (when eat--eshell-semi-char-mode
+    (push (cons #'eat--eshell-semi-char-mode
+                eat-eshell-semi-char-mode-map)
+          minor-mode-overriding-map-alist)))
+
+(define-minor-mode eat--eshell-char-mode
+  "Minor mode for char mode keymap."
+  :interactive nil
+  :keymap eat-eshell-char-mode-map
+  ;; HACK: Some keys like `C-c' are overriden by other keymaps
+  ;; (possibly by the keymaps of other minor modes), so we also put
+  ;; the keymap to `minor-mode-overriding-map-alist' to make Emacs
+  ;; prioritize us.
+  (setq minor-mode-overriding-map-alist
+        (delete (cons #'eat--eshell-char-mode
+                      eat-eshell-char-mode-map)
+                minor-mode-overriding-map-alist))
+  (when eat--eshell-char-mode
+    (push (cons #'eat--eshell-char-mode eat-eshell-char-mode-map)
+          minor-mode-overriding-map-alist)))
+
+(defun eat-eshell-emacs-mode ()
+  "Switch to Emacs keybindings mode."
+  (interactive)
+  (eat--eshell-semi-char-mode -1)
+  (eat--eshell-char-mode -1)
+  (setq buffer-read-only t)
+  (eat--grab-mouse nil eat--mouse-grabbing-type)
+  (force-mode-line-update))
+
+(defun eat-eshell-semi-char-mode ()
+  "Switch to semi-char mode."
+  (interactive)
+  (when eat--terminal
+    (setq buffer-read-only nil)
+    (eat--eshell-char-mode -1)
+    (eat--eshell-semi-char-mode +1)
+    (eat--grab-mouse nil eat--mouse-grabbing-type)
+    (force-mode-line-update)))
+
+(defun eat-eshell-char-mode ()
+  "Switch to char mode."
+  (interactive)
+  (when eat--terminal
+    (setq buffer-read-only nil)
+    (eat--eshell-semi-char-mode -1)
+    (eat--eshell-char-mode +1)
+    (eat--grab-mouse nil eat--mouse-grabbing-type)
+    (force-mode-line-update)))
+
+
+;;;;; Process Handling.
+
+(defun eat--eshell-output-filter ()
+  "Handle output from subprocess."
+  (defvar eshell-last-output-start) ; In `esh-mode'.
+  (defvar eshell-last-output-end) ; In `esh-mode'.
+  (let ((inhibit-quit t)            ; Don't disturb!
+        (inhibit-read-only t)
+        (str (buffer-substring-no-properties
+              eshell-last-output-start
+              eshell-last-output-end)))
+    (delete-region eshell-last-output-start eshell-last-output-end)
+    (let ((synchronize-scroll
+           (or (= (eat-term-display-cursor eat--terminal) (point))
+               eat--eshell-char-mode)))
+      (eat-term-process-output eat--terminal str)
+      (eat-term-redisplay eat--terminal)
+      (when synchronize-scroll
+        (funcall eat--synchronize-scroll-function)))
+    (let ((end (eat-term-end eat--terminal)))
+      (set-marker eshell-last-output-start end)
+      (set-marker eshell-last-output-end end)
+      (set-marker (process-mark eat--process) end))))
+
+(defun eat--eshell-setup-proc-and-term (proc)
+  "Setup process PROC and a new terminal for it."
+  (unless (or eat--terminal eat--process)
+    (setq eat--process proc)
+    (process-put proc 'adjust-window-size-function
+                 #'eat--adjust-process-window-size)
+    (setq eat--terminal (eat-term-make (current-buffer)
+                                       (process-mark proc)))
+    (set-marker (process-mark proc) (eat-term-end eat--terminal))
+    (setf (eat-term-input-function eat--terminal) #'eat--send-input)
+    (setf (eat-term-set-cursor-function eat--terminal)
+          #'eat--set-cursor)
+    (setf (eat-term-grab-mouse-function eat--terminal)
+          #'eat--grab-mouse)
+    (setf (eat-term-manipulate-selection-function eat--terminal)
+          #'eat--manipulate-kill-ring)
+    (setf (eat-term-ring-bell-function eat--terminal) #'eat--bell)
+    (when-let ((window (get-buffer-window nil t)))
+      (with-selected-window window
+        (eat-term-resize eat--terminal (window-max-chars-per-line)
+                         (window-text-height))))
+    (eat-term-redisplay eat--terminal)
+    (make-local-variable 'eshell-output-filter-functions)
+    (setq eshell-output-filter-functions '(eat--eshell-output-filter))
+    (eat-eshell-semi-char-mode)))
+
+(defun eat--eshell-cleanup ()
+  "Cleanup everything."
+  (defvar eshell-last-output-start) ; In `esh-mode'.
+  (defvar eshell-last-output-end) ; In `esh-mode'.
+  (when eat--terminal
+    (let ((inhibit-read-only t))
+      (goto-char (eat-term-end eat--terminal))
+      (unless (or (= (point) (point-min))
+                  (= (char-before) ?\n))
+        (insert ?\n))
+      (set-marker eshell-last-output-start (point))
+      (set-marker eshell-last-output-end (point))
+      (eat--cursor-blink-mode -1)
+      (eat--grab-mouse nil nil)
+      (eat-term-delete eat--terminal)
+      (set-process-filter eat--process #'eshell-output-filter)
+      (setq eat--terminal nil)
+      (setq eat--process nil)
+      (kill-local-variable 'eshell-output-filter-functions)
+      (eat--eshell-semi-char-mode -1)
+      (eat--eshell-char-mode -1)
+      (setq buffer-read-only nil))))
+
+(defun eat--eshell-process-output-queue (process buffer)
+  "Process the output queue on BUFFER from PROCESS."
+  (declare-function eshell-output-filter "esh-mode" (process string))
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (when eat--process-output-queue-timer
+        (cancel-timer eat--process-output-queue-timer))
+      (setq eat--output-queue-first-chunk-time nil)
+      (let ((queue eat--pending-output-chunks))
+        (setq eat--pending-output-chunks nil)
+        (combine-change-calls
+            (eat-term-beginning eat--terminal)
+            (eat-term-end eat--terminal)
+          ;; TODO: Is `string-join' OK or should we use a loop?
+          (eshell-output-filter
+           process (string-join (nreverse queue))))))))
+
+(defun eat--eshell-filter (process string)
+  "Process output STRING from PROCESS."
+  (when (buffer-live-p (process-buffer process))
+    (with-current-buffer (process-buffer process)
+      (when eat--process-output-queue-timer
+        (cancel-timer eat--process-output-queue-timer))
+      (unless eat--output-queue-first-chunk-time
+        (setq eat--output-queue-first-chunk-time (current-time)))
+      (push string eat--pending-output-chunks)
+      (let ((time-left
+             (- eat-maximum-latency
+                (float-time
+                 (time-subtract
+                  nil eat--output-queue-first-chunk-time)))))
+        (if (<= time-left 0)
+            (eat--eshell-process-output-queue
+             process (current-buffer))
+          (setq eat--process-output-queue-timer
+                (run-with-timer
+                 (min time-left eat-minimum-latency) nil
+                 #'eat--eshell-process-output-queue process
+                 (current-buffer))))))))
+
+(defun eat--eshell-sentinel (process message)
+  "Process status message MESSAGE from PROCESS."
+  (declare-function eshell-sentinel "esh-proc" (proc string))
+  (when (buffer-live-p (process-buffer process))
+    (with-current-buffer (process-buffer process)
+      (cl-letf* ((process-send-string
+                  (symbol-function #'process-send-string))
+                 ((symbol-function #'process-send-string)
+                  (lambda (proc string)
+                    (when (or (not (eq proc process))
+                              (process-live-p proc))
+                      (funcall process-send-string proc string)))))
+        (eat--eshell-process-output-queue process (current-buffer)))
+      (when (memq (process-status process) '(signal exit))
+        (eat--eshell-cleanup))))
+  (eshell-sentinel process message))
+
+;; HACK: This is a dirty hack, it can break easily.
+(defun eat--eshell-adjust-make-process-args (fn command args)
+  "Setup an environment to adjust `make-process' arguments.
+
+Call FN with COMMAND and ARGS, and whenever `make-process' is called,
+modify its argument to change the filter, the sentinel and invoke
+`stty' from the new process."
+  (cl-letf*
+      ((make-process (symbol-function #'make-process))
+       ((symbol-function #'make-process)
+        (lambda (&rest plist)
+          ;; Make sure we don't attack wrong process.
+          (if (not (and (eq (plist-get plist :filter)
+                            #'eshell-output-filter)
+                        (eq (plist-get plist :sentinel)
+                            #'eshell-sentinel)
+                        (equal (plist-get plist :command)
+                               (cons (file-local-name
+                                      (expand-file-name command))
+                                     args))))
+              (apply make-process plist)
+            (plist-put plist :filter #'eat--eshell-filter)
+            (plist-put plist :sentinel #'eat--eshell-sentinel)
+            (plist-put
+             plist :command
+             `("/usr/bin/env" "sh" "-c"
+               ,(format "stty -nl echo rows %d columns %d \
+sane 2>%s ; if [ $1 = .. ]; then shift; fi; exec \"$@\""
+                        (window-text-height)
+                        (window-max-chars-per-line) null-device)
+               ".."
+               ,@(plist-get plist :command)))
+            (let ((process (apply make-process plist)))
+              (eat--eshell-setup-proc-and-term process)
+              process)))))
+    (funcall fn command args)))
+
+
+;;;;; Minor Modes.
+
+(defun eat--eshell-synchronize-scroll ()
+  "Synchronize scrolling and point between terminal and window."
+  (when-let ((window (get-buffer-window (current-buffer))))
+    (set-window-start
+     window
+     (if (or (eat-term-in-alternative-display-p eat--terminal)
+             eat--eshell-char-mode)
+         (eat-term-display-beginning eat--terminal)
+       (save-restriction
+         (narrow-to-region
+          (eat-term-beginning eat--terminal)
+          (eat-term-end eat--terminal))
+         (let ((start-line (- (window-text-height window)
+                              (line-number-at-pos (point-max)))))
+           (goto-char (point-min))
+           (widen)
+           (if (<= start-line 0)
+               (eat-term-display-beginning eat--terminal)
+             (vertical-motion (- start-line))
+             (point)))))))
+  (goto-char (eat-term-display-cursor eat--terminal)))
+
+(define-minor-mode eat--eshell-local-mode
+  "Toggle Eat terminal emulation is Eshell."
+  :interactive nil
+  :keymap eat-eshell-emacs-mode-map
+  (cond
+   (eat--eshell-local-mode
+    (make-local-variable 'cursor-type)
+    (make-local-variable 'glyphless-char-display)
+    (make-local-variable 'track-mouse)
+    (make-local-variable 'filter-buffer-substring-function)
+    (make-local-variable 'eat--terminal)
+    (make-local-variable 'eat--process)
+    (make-local-variable 'eat--synchronize-scroll-function)
+    (make-local-variable 'eat--mouse-grabbing-type)
+    (make-local-variable 'eat--pending-output-chunks)
+    (make-local-variable 'eat--output-queue-first-chunk-time)
+    (make-local-variable 'eat--process-output-queue-timer)
+    (setq eat--synchronize-scroll-function
+          #'eat--eshell-synchronize-scroll)
+    (setq filter-buffer-substring-function
+          #'eat--filter-buffer-substring)
+    ;; Make sure glyphless character don't display a huge box glyph,
+    ;; that would break the display.
+    (eat--setup-glyphless-chars)
+    (when eat-enable-blinking-text
+      (eat-blink-mode +1)))
+   (t
+    (when eat-enable-blinking-text
+      (eat-blink-mode -1))
+    (kill-local-variable 'cursor-type)
+    (kill-local-variable 'glyphless-char-display)
+    (kill-local-variable 'track-mouse)
+    (make-local-variable 'filter-buffer-substring-function)
+    (kill-local-variable 'eat--terminal)
+    (kill-local-variable 'eat--process)
+    (kill-local-variable 'eat--synchronize-scroll-function)
+    (kill-local-variable 'eat--mouse-grabbing-type)
+    (kill-local-variable 'eat--pending-output-chunks)
+    (kill-local-variable 'eat--output-queue-first-chunk-time)
+    (kill-local-variable 'eat--process-output-queue-timer))))
+
+;;;###autoload
+(define-minor-mode eat-eshell-mode
+  "Toggle Eat terminal emulation is Eshell."
+  :global t
+  :lighter (eat--eshell-local-mode
+            (" Eat-Eshell"
+             (:eval
+              (when eat--terminal
+                (cond
+                 (eat--eshell-semi-char-mode
+                  `("["
+                    (:propertize
+                     "semi-char"
+                     help-echo
+                     ,(concat "mouse-1: Switch to char mode, "
+                              "mouse-3: Switch to emacs mode")
+                     mouse-face mode-line-highlight
+                     local-map
+                     (keymap
+                      (mode-line
+                       . (keymap
+                          (down-mouse-1 . eat-eshell-char-mode)
+                          (down-mouse-3 . eat-eshell-emacs-mode)))))
+                    "]"))
+                 (eat--eshell-char-mode
+                  '("["
+                    (:propertize
+                     "char"
+                     help-echo
+                     ,(concat "mouse-1: Switch to semi-char mode, "
+                              "mouse-3: Switch to emacs mode")
+                     mouse-face mode-line-highlight
+                     local-map
+                     (keymap
+                      (mode-line
+                       . (keymap
+                          (down-mouse-1 . eat-eshell-semi-char-mode)
+                          (down-mouse-3 . eat-eshell-emacs-mode)))))
+                    "]"))
+                 (t
+                  `("["
+                    (:propertize
+                     "emacs"
+                     help-echo
+                     ,(concat "mouse-1: Switch to semi-char mode, "
+                              "mouse-3: Switch to char mode")
+                     mouse-face mode-line-highlight
+                     local-map
+                     (keymap
+                      (mode-line
+                       . (keymap
+                          (down-mouse-1 . eat-eshell-semi-char-mode)
+                          (down-mouse-3 . eat-eshell-char-mode)))))
+                    "]")))))))
+  :group 'eat-ehell
+  (defvar eshell-variable-aliases-list) ; In `esh-var'.
+  (defvar eshell-last-async-procs) ; In `esh-cmd'.
+  (declare-function eshell-gather-process-output "esh-proc"
+                    (command args))
+  (cond
+   (eat-eshell-mode
+    (let ((buffers nil))
+      (setq eat-eshell-mode nil)
+      (require 'esh-mode)
+      (require 'esh-proc)
+      (require 'esh-var)
+      (require 'esh-cmd)
+      (dolist (buffer (buffer-list))
+        (with-current-buffer buffer
+          (when (eq major-mode #'eshell-mode)
+            (when eshell-last-async-procs
+              (user-error
+               (concat "Can't toggle Eat Eshell mode while"
+                       " any Eshell process is running")))
+            (push buffer buffers))))
+      (setq eat-eshell-mode t)
+      (dolist (buffer buffers)
+        (with-current-buffer buffer
+          (eat--eshell-local-mode +1))))
+    (add-hook 'eshell-mode-hook #'eat--eshell-local-mode)
+    (setq eshell-variable-aliases-list
+          `(("TERM" eat-term-name t t)
+            ("TERMINFO" eat-term-terminfo-directory t)
+            ("INSIDE_EMACS" eat-term-inside-emacs t)
+            ,@eshell-variable-aliases-list))
+    (advice-add #'eshell-gather-process-output :around
+                #'eat--eshell-adjust-make-process-args))
+   (t
+    (let ((buffers nil))
+      (setq eat-eshell-mode t)
+      (dolist (buffer (buffer-list))
+        (with-current-buffer buffer
+          (when (and (eq major-mode #'eshell-mode)
+                     eat--eshell-local-mode)
+            (when eshell-last-async-procs
+              (user-error
+               (concat "Can't toggle Eat Eshell mode while"
+                       " any Eshell process is running")))
+            (push buffer buffers))))
+      (setq eat-eshell-mode nil)
+      (dolist (buffer buffers)
+        (with-current-buffer buffer
+          (eat--eshell-local-mode -1))))
+    (remove-hook 'eshell-mode-hook #'eat--eshell-local-mode)
+    (setq eshell-variable-aliases-list
+          (cl-delete-if
+           (lambda (elem)
+             (member elem
+                     '(("TERM" eat-term-name t t)
+                       ("TERMINFO" eat-term-terminfo-directory t)
+                       ("INSIDE_EMACS" eat-term-inside-emacs t))))
+           eshell-variable-aliases-list))
+    (advice-remove #'eshell-gather-process-output
+                   #'eat--eshell-adjust-make-process-args))))
+
+
+;;;; Eshell Visual Command Handling.
+
+;; Adapted from `em-term'.
+(defun eat--eshell-visual-sentinel (proc _msg)
+  "Clean up the buffer visiting PROC.
+
+If `eshell-destroy-buffer-when-process-dies' is non-nil, destroy
+the buffer.
+
+MSG describes PROC's status."
+  (defvar eshell-destroy-buffer-when-process-dies) ; In `em-term'.
+  (when eshell-destroy-buffer-when-process-dies
+    (let ((proc-buf (process-buffer proc)))
+      (when (and proc-buf (buffer-live-p proc-buf)
+                 (not (eq 'run (process-status proc)))
+                 (= (process-exit-status proc) 0))
+        (if (eq (current-buffer) proc-buf)
+            (when-let ((buf (and (boundp 'eshell-parent-buffer)
+                                 (buffer-live-p eshell-parent-buffer)
+                                 eshell-parent-buffer)))
+              (switch-to-buffer buf)))
+        (kill-buffer proc-buf)))))
+
+(defun eat--eshell-exec-visual (&rest args)
+  "Run the specified PROGRAM in a terminal emulation buffer.
+
+ARGS are passed to the program.  At the moment, no piping of input is
+allowed."
+  (declare-function eshell-find-interpreter "esh-ext"
+                    (file args &optional no-examine-p))
+  (declare-function eshell-stringify-list "esh-util" (args))
+  (defvar eshell-interpreter-alist) ; In `esh-ext'.
+  (require 'esh-ext)
+  (require 'esh-util)
+  (let* (eshell-interpreter-alist
+         (interp (eshell-find-interpreter (car args) (cdr args)))
+         (program (car interp))
+         (args (flatten-tree
+                (eshell-stringify-list (append (cdr interp)
+                                               (cdr args)))))
+         (eat-buf
+          (generate-new-buffer
+           (concat "*" (file-name-nondirectory program) "*")))
+         (eshell-buf (current-buffer)))
+    (with-current-buffer eat-buf
+      (switch-to-buffer eat-buf)
+      (eat-mode)
+      (setq-local eshell-parent-buffer eshell-buf)
+      (setq-local eat-kill-buffer-on-exit nil)
+      (eat-exec eat-buf program program nil args)
+      (let ((proc (get-buffer-process eat-buf)))
+        (if (and proc (eq 'run (process-status proc)))
+            (let ((sentinel (process-sentinel proc)))
+              (add-function  :after (var sentinel)
+                             #'eat--eshell-visual-sentinel)
+              (set-process-sentinel proc sentinel))
+          (error "Failed to invoke visual command")))
+      (eat-semi-char-mode)))
+  nil)
+
+;;;###autoload
+(define-minor-mode eat-eshell-visual-command-mode
+  "Toggle running Eshell visual commands with Eat."
+  :group 'eat-eshell
+  :global t
+  (declare-function eshell-exec-visual "em-term" (&rest args))
+  (if eat-eshell-visual-command-mode
+      (advice-add #'eshell-exec-visual :override
+                  #'eat--eshell-exec-visual)
+    (advice-remove #'eshell-exec-visual #'eat--eshell-exec-visual)))
+
+
+;;;; Project Integration.
+
+;;;###autoload
+(defun eat-project (&optional arg)
+  "Start Eat in the current project's root directory.
+
+Start a new Eat session, or switch to an already active session.
+Return the buffer selected (or created).
+
+With a non-numeric prefix ARG, create a new session.
+
+With a numeric prefix ARG (like \\[universal-argument] 42 \\[eshell]),
+switch to the session with that number, or create it if it doesn't
+already exist."
+  (interactive "P")
+  (declare-function project-root "project" (project))
+  (declare-function project-prefixed-buffer-name "project" (mode))
+  (require 'project)
+  (let* ((default-directory (project-root (project-current t)))
+         (eat-buffer-name (project-prefixed-buffer-name "eat")))
+    (eat nil arg)))
+
+
+;;;; Tracing.
+
+;;;;; Recording Trace Data.
+
+(defconst eat--trace-recorded-variables
+  '(eat-term-scrollback-size
+    eat-enable-alternative-display)
+  "The variable to record in trace output.")
+
+(defvar eat--trace-output-buffer nil
+  "Buffer where the trace data is written to.")
+
+(defun eat--trace-log (time operation &rest args)
+  "Log TIME, OPERATION and ARGS into trace output.
+
+TIME defaults to the current time.
+
+The current buffer should be the trace output buffer.  Move the point
+to the end of (accessible portion of) buffer."
+  (goto-char (point-max))
+  ;; Hope that `float-time' won't roll over while tracing.  ;-)
+  (insert (replace-regexp-in-string
+           "\n" "\\\\n"
+           (format "%S" `(,(float-time time) ,operation ,@args)))
+          ?\n))
+
+(defun eat--trace-stop ()
+  "Stop tracing the terminal in current buffer."
+  (when eat--trace-output-buffer
+    (with-current-buffer eat--trace-output-buffer
+      (eat--trace-log nil 'finish)))
+  (remove-hook 'kill-buffer-hook #'eat--trace-stop t)
+  (kill-local-variable 'eat--trace-output-buffer))
+
+(defun eat--trace-exec (fn buffer name command startfile switches)
+  "Trace `eat-exec'.
+
+BUFFER is the buffer and COMMAND and SWITCHES are the invocation
+command.  BUFFER, NAME, COMMAND, STARTFILE and SWITCHES are passed to
+FN, `eat-exec', which see."
+  (let ((time (current-time)))
+    (prog1
+        (funcall fn buffer name command startfile switches)
+      (let ((buf (generate-new-buffer
+                  (format "*eat-trace %s*: %s"
+                          (buffer-name buffer)
+                          (mapconcat #'shell-quote-argument
+                                     (cons command switches) " "))))
+            (width nil)
+            (height nil)
+            (variables nil))
+        (with-current-buffer buffer
+          (setq-local eat--trace-output-buffer buf)
+          (add-hook 'kill-buffer-hook #'eat--trace-stop nil t)
+          (let ((size (eat-term-size eat--terminal)))
+            (setq width (car size))
+            (setq height (cdr size)))
+          (dolist (var eat--trace-recorded-variables)
+            (push (cons var (symbol-value var)) variables)))
+        (with-current-buffer buf
+          (lisp-data-mode)
+          (insert ";; -*- lisp-data -*-\n")
+          (eat--trace-log time 'create 'eat width height
+                          variables))))))
+
+(defun eat--trace-process-output-queue (fn buffer)
+  "Trace `eat--process-output-queue'.
+
+BUFFER is passed to FN, `eat--process-output-queue', which see."
+  (if (or (not (buffer-live-p buffer))
+          (not (buffer-local-value 'eat--trace-output-buffer buffer)))
+      (funcall fn buffer)
+    (cl-letf* ((eat-term-process-output
+                (symbol-function #'eat-term-process-output))
+               ((symbol-function #'eat-term-process-output)
+                (lambda (terminal output)
+                  (when (buffer-live-p eat--trace-output-buffer)
+                    (with-current-buffer eat--trace-output-buffer
+                      (eat--trace-log nil 'output output)))
+                  (funcall eat-term-process-output terminal output)))
+               (eat-term-redisplay
+                (symbol-function #'eat-term-redisplay))
+               ((symbol-function #'eat-term-redisplay)
+                (lambda (terminal)
+                  (when (buffer-live-p eat--trace-output-buffer)
+                    (with-current-buffer eat--trace-output-buffer
+                      (eat--trace-log nil 'redisplay)))
+                  (funcall eat-term-redisplay terminal))))
+      (funcall fn buffer))))
+
+(defun eat--trace-adjust-process-window-size (fn process windows)
+  "Trace `eat--adjust-process-window-size'.
+
+PROCESS and WINDOWS are passed to FN,
+`eat--adjust-process-window-size', which see."
+  (cl-letf*
+      ((eat-term-resize (symbol-function #'eat-term-resize))
+       ((symbol-function #'eat-term-resize)
+        (lambda (terminal width height)
+          (when (buffer-live-p eat--trace-output-buffer)
+            (with-current-buffer eat--trace-output-buffer
+              (eat--trace-log nil 'resize width height)))
+          (funcall eat-term-resize terminal width height)))
+       (eat-term-redisplay (symbol-function #'eat-term-redisplay))
+       ((symbol-function #'eat-term-redisplay)
+        (lambda (terminal)
+          (when (buffer-live-p eat--trace-output-buffer)
+            (with-current-buffer eat--trace-output-buffer
+              (eat--trace-log nil 'redisplay)))
+          (funcall eat-term-redisplay terminal))))
+    (funcall fn process windows)))
+
+(defun eat--trace-sentinel (fn &rest args)
+  "Trace `eat--sentinel'.
+
+Elements of ARGS are passed to FN, `eat--sentinel', which see."
+  (cl-letf* ((eat-term-delete (symbol-function #'eat-term-delete))
+             ((symbol-function #'eat-term-delete)
+              (lambda (terminal)
+                (when (buffer-live-p eat--trace-output-buffer)
+                  (eat--trace-stop))
+                (funcall eat-term-delete terminal))))
+    (apply fn args)))
+
+(defun eat--trace-reset (fn)
+  "Trace `eat-reset'.
+
+FN is original definition of `eat-reset'."
+  (cl-letf*
+      ((eat-term-reset (symbol-function #'eat-term-reset))
+       ((symbol-function #'eat-term-reset)
+        (lambda (terminal)
+          (when (buffer-live-p eat--trace-output-buffer)
+            (with-current-buffer eat--trace-output-buffer
+              (eat--trace-log nil 'reset)))
+          (funcall eat-term-reset terminal)))
+       (eat-term-redisplay (symbol-function #'eat-term-redisplay))
+       ((symbol-function #'eat-term-redisplay)
+        (lambda (terminal)
+          (when (buffer-live-p eat--trace-output-buffer)
+            (with-current-buffer eat--trace-output-buffer
+              (eat--trace-log nil 'redisplay)))
+          (funcall eat-term-redisplay terminal))))
+    (funcall fn)))
+
+(defun eat--eshell-trace-adjust-make-process-args (fn &rest args)
+  "Trace `eat--eshell-adjust-make-process-args'.
+
+ARGS is passed to FN, `eat--eshell-adjust-make-process-args', which
+see."
+  (cl-letf*
+      ((command nil)
+       (make-process (symbol-function #'make-process))
+       ((symbol-function #'make-process)
+        (lambda (&rest plist)
+          (prog1
+              (apply make-process plist)
+            (setq command (nthcdr 5 (plist-get plist :command))))))
+       (eat--eshell-setup-proc-and-term
+        (symbol-function #'eat--eshell-setup-proc-and-term))
+       ((symbol-function #'eat--eshell-setup-proc-and-term)
+        (lambda (proc)
+          (let ((time (current-time)))
+            (prog1
+                (funcall eat--eshell-setup-proc-and-term proc)
+              (when (eq eat--process proc)
+                (let ((buf (generate-new-buffer
+                            (format "*eat-trace %s*: %s"
+                                    (buffer-name)
+                                    (mapconcat
+                                     #'shell-quote-argument
+                                     command " "))))
+                      (width nil)
+                      (height nil)
+                      (variables nil))
+                  (setq-local eat--trace-output-buffer buf)
+                  (add-hook 'kill-buffer-hook #'eat--trace-stop nil t)
+                  (let ((size (eat-term-size eat--terminal)))
+                    (setq width (car size))
+                    (setq height (cdr size)))
+                  (dolist (var eat--trace-recorded-variables)
+                    (push (cons var (symbol-value var)) variables))
+                  (with-current-buffer buf
+                    (lisp-data-mode)
+                    (insert ";; -*- lisp-data -*-\n")
+                    (eat--trace-log time 'create 'eshell width height
+                                    variables)))))))))
+    (apply fn args)))
+
+(defun eat--eshell-trace-output-filter (fn)
+  "Trace `eat--eshell-output-filter'.
+
+FN is the original definition of `eat--eshell-output-filter', which
+see."
+  (if (not (buffer-live-p eat--trace-output-buffer))
+      (funcall fn)
+    (cl-letf* ((eat-term-process-output
+                (symbol-function #'eat-term-process-output))
+               ((symbol-function #'eat-term-process-output)
+                (lambda (terminal output)
+                  (with-current-buffer eat--trace-output-buffer
+                    (eat--trace-log nil 'output output))
+                  (funcall eat-term-process-output terminal output)))
+               (eat-term-redisplay
+                (symbol-function #'eat-term-redisplay))
+               ((symbol-function #'eat-term-redisplay)
+                (lambda (terminal)
+                  (with-current-buffer eat--trace-output-buffer
+                    (eat--trace-log nil 'redisplay))
+                  (funcall eat-term-redisplay terminal))))
+      (funcall fn))))
+
+(defun eat--eshell-trace-cleanup (fn)
+  "Trace `eat--eshell-cleanup'.
+
+FN is the original definition of `eat--eshell-cleanup', which see."
+  (if (not (buffer-live-p eat--trace-output-buffer))
+      (funcall fn)
+    (cl-letf* ((eat-term-delete (symbol-function #'eat-term-delete))
+               ((symbol-function #'eat-term-delete)
+                (lambda (terminal)
+                  (eat--trace-stop)
+                  (funcall eat-term-delete terminal))))
+      (funcall fn))))
+
+(define-minor-mode eat-trace-mode
+  "Toggle tracing Eat terminal."
+  :global t
+  :require 'eat
+  :lighter " Eat-Trace"
+  (if eat-trace-mode
+      (progn
+        (advice-add #'eat-exec :around #'eat--trace-exec)
+        (advice-add #'eat--process-output-queue :around
+                    #'eat--trace-process-output-queue)
+        (advice-add #'eat--adjust-process-window-size :around
+                    #'eat--trace-adjust-process-window-size)
+        (advice-add #'eat--sentinel :around #'eat--trace-sentinel)
+        (advice-add #'eat-reset :around #'eat--trace-reset)
+        (advice-add #'eat--eshell-adjust-make-process-args :around
+                    #'eat--eshell-trace-adjust-make-process-args)
+        (advice-add #'eat--eshell-output-filter :around
+                    #'eat--eshell-trace-output-filter)
+        (advice-add #'eat--eshell-cleanup :around
+                    #'eat--eshell-trace-cleanup))
+    (advice-remove #'eat-exec #'eat--trace-exec)
+    (advice-remove #'eat--process-output-queue
+                   #'eat--trace-process-output-queue)
+    (advice-remove #'eat--adjust-process-window-size
+                   #'eat--trace-adjust-process-window-size)
+    (advice-remove #'eat--sentinel #'eat--trace-sentinel)
+    (advice-remove #'eat-reset #'eat--trace-reset)
+    (advice-remove #'eat--eshell-adjust-make-process-args
+                   #'eat--eshell-trace-adjust-make-process-args)
+    (advice-remove #'eat--eshell-output-filter
+                   #'eat--eshell-trace-output-filter)
+    (advice-remove #'eat--eshell-cleanup
+                   #'eat--eshell-trace-cleanup)
+    (dolist (buffer (buffer-list))
+      (when (buffer-local-value 'eat--trace-output-buffer buffer)
+        (with-current-buffer buffer
+          (setq-local eat--trace-output-buffer nil))))))
+
+
+;;;;; Trace Data Replay.
+
+(defvar eat--trace-replay-buffer nil
+  "The buffer replaying the trace data in current buffer.")
+
+(defvar eat--trace-replay-marker nil
+  "The point from where to read the next sexp.")
+
+(defvar eat--trace-replay-current-sexp-overlay nil
+  "Overlay indicating the current sexp.")
+
+(defvar eat--trace-replay-source-buffer nil
+  "The source buffer containing the trace output.")
+
+(defvar eat--trace-replay-recording-start-time 0.0
+  "Time when recording was started.")
+
+(defvar eat--trace-replay-frame-count 0
+  "The number of the frames in the trace output.")
+
+(defvar eat--trace-replay-progress-frame 0
+  "The number of the frames before the current position.")
+
+(defvar eat--trace-replay-progress nil
+  "The number of seconds of trace output was shown.")
+
+(defun eat--trace-replay-eval (data)
+  "Evalulate DATA as trace output."
+  (let ((inhibit-read-only t))
+    (setq eat--trace-replay-progress
+          (- (car data) eat--trace-replay-recording-start-time))
+    (pcase data
+      (`(,time create ,_ui ,width ,height ,variables)
+       (setq eat--trace-replay-recording-start-time time)
+       (setq eat--trace-replay-progress 0)
+       (dolist (var eat--trace-recorded-variables)
+         (set (make-local-variable var) (alist-get var variables)))
+       (setq eat--terminal (eat-term-make (current-buffer) (point)))
+       (setf (eat-term-set-cursor-function eat--terminal)
+             #'eat--set-cursor)
+       (setf (eat-term-ring-bell-function eat--terminal) #'eat--bell)
+       (eat-term-resize eat--terminal width height)
+       (eat-term-redisplay eat--terminal))
+      (`(,_time output ,string)
+       (eat-term-process-output eat--terminal string))
+      (`(,_time redisplay)
+       (eat-term-redisplay eat--terminal))
+      (`(,_time resize ,width ,height)
+       (eat-term-resize eat--terminal width height))
+      (`(,_time reset)
+       (eat-term-reset eat--terminal))
+      (`(,_time finish)
+       (eat-term-delete eat--terminal)))
+    (eat--synchronize-scroll)))
+
+(defun eat--trace-replay-eval-next ()
+  "Evaluate next sexp in trace output."
+  (with-current-buffer eat--trace-replay-source-buffer
+    (goto-char eat--trace-replay-marker)
+    (ignore-error end-of-file
+      (let ((data (read (current-buffer))))
+        (set-marker eat--trace-replay-marker (point))
+        (backward-list)
+        (move-overlay eat--trace-replay-current-sexp-overlay
+                      (point) (point))
+        (when-let ((window (get-buffer-window)))
+          (set-window-point window (point)))
+        (with-current-buffer eat--trace-replay-buffer
+          (cl-incf eat--trace-replay-progress-frame)
+          (eat--trace-replay-eval data))))))
+
+(defun eat-trace-replay ()
+  "Replay terminal according to trace output in current buffer."
+  (interactive)
+  (unless (buffer-live-p eat--trace-replay-buffer)
+    (setq-local eat--trace-replay-buffer
+                (generate-new-buffer
+                 (format "*eat-trace-replay*: %s" (buffer-name))))
+    (setq-local eat--trace-replay-marker (point-min-marker))
+    (let ((ov (make-overlay (point-min) (point-min))))
+      (overlay-put ov 'before-string
+                   (propertize " " 'display
+                               '(left-fringe right-triangle)))
+      (setq-local eat--trace-replay-current-sexp-overlay ov))
+    (goto-char (point-min))
+    (let ((source (current-buffer))
+          (frame-count 0))
+      (ignore-error end-of-file
+        (while (read (current-buffer))
+          (cl-incf frame-count)))
+      (goto-char (point-min))
+      (with-current-buffer eat--trace-replay-buffer
+        (eat-trace-replay-mode)
+        (setq eat--trace-replay-source-buffer source)
+        (setq eat--trace-replay-frame-count frame-count))))
+  (display-buffer eat--trace-replay-buffer))
+
+(defun eat-trace-replay-next-frame (&optional n)
+  "Show the Nth next frame.
+
+N defaults to 1.  Interactively, N is the prefix argument."
+  (interactive "p")
+  (dotimes (_ n)
+    (eat--trace-replay-eval-next)))
+
+(defun eat-trace--cleanup ()
+  "Clean up the source buffer before the terminal being killed."
+  (when (buffer-live-p eat--trace-replay-source-buffer)
+    (with-current-buffer eat--trace-replay-source-buffer
+      (setq eat--trace-replay-buffer nil)
+      (setq eat--trace-replay-marker nil)
+      (delete-overlay eat--trace-replay-current-sexp-overlay))))
+
+(defvar eat-trace-replay-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "n") #'eat-trace-replay-next-frame)
+    (define-key map (kbd "<down>") #'eat-trace-replay-next-frame)
+    (define-key map (kbd "q") #'quit-window)
+    map)
+  "Keymap for Eat-Trace-Replay mode.")
+
+(define-derived-mode eat-trace-replay-mode special-mode
+  "Eat-Trace-Replay"
+  "Major mode for replaying terminal according to trace output."
+  (make-local-variable 'eat--terminal)
+  (make-local-variable 'eat--trace-replay-source-buffer)
+  (make-local-variable 'eat--trace-replay-recording-start-time)
+  (make-local-variable 'eat--trace-replay-progress)
+  (make-local-variable 'eat--trace-replay-frame-count)
+  (make-local-variable 'eat--trace-replay-progress-frame)
+  (setq-local
+   mode-line-process
+   '("[" (:eval (number-to-string eat--trace-replay-progress-frame))
+     "/" (:eval (number-to-string eat--trace-replay-frame-count))
+     "]"))
+  (add-hook 'kill-buffer-hook #'eat-trace--cleanup nil t))
+
+(provide 'eat)
+;;; eat.el ends here
diff --git a/eat.texi b/eat.texi
new file mode 100644
index 0000000000..aa5e128e8f
--- /dev/null
+++ b/eat.texi
@@ -0,0 +1,1001 @@
+\input texinfo
+
+@comment %**start of header
+@setfilename eat.info
+@set UPDATED 17 November 2022
+@set EDITION 0.1snapshot
+@set VERSION 0.1snapshot
+@documentencoding UTF-8
+@codequotebacktick on
+@codequoteundirected on
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex ky cp
+@settitle Eat User Manual, version @value{VERSION}
+@comment %**end of header
+
+@copying
+This manual is for Eat (version @value{VERSION}, @value{UPDATED}), a
+terminal emulator for Emacs.
+
+Copyright @copyright{}  2022  Akib Azmain Turja.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
+copy of the license is included in the section entitled ``GNU Free
+Documentation License''.
+@end quotation
+@end copying
+
+@dircategory Emacs
+@direntry
+* Eat: (eat).           Emulate A Terminal.
+@end direntry
+
+@titlepage
+@title Eat User Manual
+@subtitle For version @value{VERSION}
+@author Akib Azmain Turja
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top Eat Manual
+@insertcopying
+@end ifnottex
+
+@menu
+Introduction
+* Intro::               What is Eat?
+* Hello Terminal::      Starting Eat's terminal for the first time.
+* Project-local Terminal::  One project, one terminal.
+* Eshell Terminal::     Eat's terminal emulation in Eshell.
+
+Basic Operations
+* Keyboard::            Most keyboard keys are captured by Eat.
+* Mouse::               Eat supports mouse.
+* Input Modes::         Input modes for various use-cases.
+
+Advanced Customizations
+* Display::             The region where everything is shown.
+* Scrollback::          Region for things that went out of display.
+* Cursor Types::        Cursor can displayed in many forms.
+* Mouse Tracking::      Eat tracks mouse, but this can be changed.
+* Clipboard::           Integrating kill ring with terminal.
+* Colors::              Eat can show more than sixteen million colors.
+* Fonts::               Eat can show up to sixty font different fonts.
+* Blinking Text::       Annoying blinking texts.
+* Performance Tuning::  Fine tuning to maximize performance.
+
+Recovering from Problems
+* Common Problems::     Common problem, and fixes.
+* Reporting Bugs::      How to report problems?
+* Tracing the Terminal::  Gathering some crucial information to
+                          reproduce a bug.
+
+Appendices
+* GNU General Public License::  Copying condition for Eat.
+* GNU Free Documentation License::  Copying conditions of this manual.
+* Index::               A list of various things.
+@end menu
+
+@part Part I:@* Introduction
+
+@node Intro
+@cindex introduction
+@chapter Introduction
+
+@abbr{Eat, Emulate A Terminal} is a terminal emulator for Emacs.  It
+emulates a XTerm-like terminal, just like many other terminal
+emulators.  But it has some key features that make Eat distinct from
+other terminal emulators.
+
+Firstly, it's in Emacs, which means you don't need to leave the
+comfort of Emacs to use Emacs.
+
+Secondly, it's easy and convenient to use.  It is tries to stay out of
+your way, allow you to maximize your productivity.
+
+Finally, special care has been taken while designing the keybindings,
+so that the terminal doesn't conflict with Emacs default keybindings
+on both graphical display and text display, while still allowing you
+to run full screen programs like Emacs within the terminal.
+
+@node Hello Terminal
+@cindex hello terminal
+@cindex terminal, hello
+@chapter Hello Terminal
+
+@findex eat
+The terminal can be started with @kbd{M-x eat}.  It would prompt you
+for the program to run in the terminal, with a reasonable default
+value already filled in.  You can specify a program path, or a shell
+command.  After you hit @kbd{@key{RET}}, you will see a terminal, and
+the program you chose will be run within the terminal in the current
+directory.  You can interact with it.  If you started a shell, you
+should get a shell prompt and you should be able to write commands and
+execute them.  Full screen programs like @samp{htop}, @samp{lynx} and
+Emacs will work inside it, just like other any other terminal.
+
+If an Eat terminal already exists, @kbd{M-x eat} will switch to it.
+To create a new terminal, call it with a prefix argument like this,
+@kbd{C-u M-x eat}.
+
+If you give it a numeric argument N, for example @kbd{C-u 42 M-x eat},
+it'll switch to a terminal in @file{*eat*<N>}, @file{*eat*<42>} for
+example, and it'll create a new terminal if that doesn't exist.
+
+@node Project-local Terminal
+@cindex project-local terminal
+@cindex terminal, project-local
+@cindex project's terminal
+@cindex project terminal
+@cindex terminal, project
+@chapter Project-local Terminal
+
+@findex eat-project
+Usually, you don't use a single terminal for everything, instead you
+open a terminal for each project that needs it.  So there is command
+named @command{eat-project}.  It opens a new terminal in project root
+directory, or switches to a already existing project terminal.  It too
+accepts prefix argument, just like the ordinary @command{eat} command.
+
+@node Eshell Terminal
+@cindex eshell terminal
+@cindex terminal, eshell
+@cindex eshell terminal emulation
+@cindex terminal emulation, eshell
+@cindex eat, eshell
+@cindex eshell, eat
+@cindex eshell
+@chapter Eshell Terminal Emulation
+
+Eat also supports terminal emulation outside Eat's terminal.  So you
+can emulate terminal in Eshell (@pxref{Top,,, eshell, Eshell manual})
+with Eat.  After configuring Eshell to use Eat for terminal emulation,
+you can run any full screen terminal program in Eshell.
+
+@findex eat-eshell-mode
+To enable terminal emulation in Eshell, enable the global minor mode
+@command{eat-eshell-mode}.  It will enable Eat's terminal emulation in
+Eshell.  To disable the terminal emulation, disable the minor mode.
+
+You can't toggle the global minor mode while any Eshell command is
+running, so terminate any Eshell command or wait them to finish before
+toggling the mode.
+
+Unless stated otherwise, everything described in this manual about
+Eat terminal also applies to Eshell terminal emulation.
+
+@part Part II:@* Basic Operations
+
+@node Keyboard
+@cindex keyboard
+@chapter Keyboard
+
+Just like any other text terminal, the primary interaction device with
+Eat terminal is the keyboard.  Eat forwards all supported keyboard
+events like @kbd{a}, @kbd{E}, @kbd{RET}, @kbd{C-a} to the terminal.
+
+However, this conflict with Emacs keybinding conventions, and makes it
+almost impossible to call any other Emacs command.  So, by default,
+Eat doesn't intercept the key sequences beginning with the following
+keys and lets Emacs to handle them: @kbd{C-\}, @kbd{C-c}, @kbd{C-x},
+@kbd{C-g}, @kbd{C-h}, @kbd{C-M-c}, @kbd{C-u}, @kbd{C-q}, @kbd{M-x},
+@kbd{M-:}, @kbd{M-!} and @kbd{M-&}.
+
+To input the above key sequences, prefix them with @kbd{C-q}.
+@kbd{C-q} reads the next event and sends to directly to the terminal.
+For example, to input @kbd{M-:}, use the key sequence @kbd{C-q M-:}.
+
+For an alternative way to input these exceptional characters,
+@pxref{Char Mode}.
+
+@node Mouse
+@cindex mouse
+@chapter Mouse
+
+Eat supports mouse tracking.  That means in programs like Emacs,
+@samp{htop}, etc, that support mouse, you can hover and click on
+text and buttons.  You can also use your mouse wheel to scroll text,
+if the program supports it.
+
+@xref{Mouse Tracking} to configure mouse tracking.
+
+@node Input Modes
+@cindex input modes
+@cindex modes, input
+@cindex keybinding modes
+@cindex modes, keybinding
+@chapter Input Modes
+
+By default, Eat forwards all supported keys to terminals, except some
+exceptions.  It is possible to input them with @kbd{C-q}, but it is
+not very convenient.
+
+To conveniently input those character, they should be bound to input
+themselves to the terminal (i.e. pressing @kbd{M-x} will input
+@kbd{M-x}, bypassing Emacs).  But this is conflicts with Emacs's
+default keybindings, so this can't done, at least by default.
+
+To overcome the problem, Eat implements several ``input modes''.  Each
+input mode has a different set of keybindings for different
+applications.
+
+@anchor{Semi-char Mode}
+@cindex semi-char mode
+@cindex mode, semi-char
+@cindex keybindings, semi-char mode
+@cindex keybinding mode, semi-char
+@cindex input mode, semi-char
+@section Semi-char Mode
+
+``Semi-char mode'' is the default input mode of Eat.  This works for
+most inputs.  It forwards all keys, except @kbd{C-\}, @kbd{C-c},
+@kbd{C-x}, @kbd{C-g}, @kbd{C-h}, @kbd{C-M-c}, @kbd{C-u}, @kbd{M-x},
+@kbd{C-q}, @kbd{M-:}, @kbd{M-!} and @kbd{M-&}, Emacs handle them.
+
+@cindex inputting exceptional characters
+@kindex C-q @r{(``semi-char mode'')}
+To input these exceptions, there is a key @kbd{C-q}.  This reads the
+next input event and sends that as the input.  For example, the key
+sequences @kbd{C-q M-:} inputs @kbd{M-:}, @kbd{C-q C-g} inputs
+@kbd{C-g}.
+
+Input methods (@pxref{Input Methods,,, emacs, GNU Emacs Manual}) work
+in this mode, so, unlike Term (@pxref{Terminal emulator, Emacs
+Terminal Emulator, Emacs Terminal Emulator, emacs, GNU Emacs Manual}),
+Emacs built-in terminal emulator, you can still input any character.
+
+@kindex C-c C-c @r{(``semi-char mode'')}
+@kindex C-c C-k @r{(``semi-char mode'')}
+In ``semi-char mode'', @kbd{C-c C-c} sends a @kbd{C-c}, just for
+convenience, and @kbd{C-c C-k} kills the terminal program.
+
+@anchor{Char Mode}
+@cindex char mode
+@cindex mode, char
+@cindex keybindings, char mode
+@cindex keybinding mode, char
+@cindex input mode, char
+@section Char Mode
+
+By default, Eat is in ``semi-char mode''.  In this input mode, Eat
+forwards all supported keys to terminals, except some exceptions,
+@pxref{Semi-char Mode}.  It is possible to input them with @kbd{C-q},
+but it is not very convenient.
+
+@kindex C-c M-d @r{(``semi-char mode'')}
+To overcome this problem, Eat implements another input mode called
+``char mode''.  To switch to ``char mode'', press @kbd{C-c M-d} in
+``semi-char mode''.  In Eshell, the command
+@command{eshell-toggle-direct-send} is remapped to enable
+``char-mode'', which is usually bound to @kbd{C-c M-d}.
+
+In this input mode, Eat forwards all supported keys.  However, input
+methods still work in this mode, so you can still input keys that are
+not on your keyboard.
+
+@kindex C-M-m @r{(``char mode'')}
+@kindex M-RET @r{(``char mode'')}
+To get out of ``char mode'', press @kbd{C-M-m} or @kbd{M-@key{RET}},
+this switches back to ``semi-char mode''.
+
+@anchor{Emacs Mode}
+@cindex emacs mode
+@cindex mode, emacs
+@cindex keybindings, emacs mode
+@cindex keybinding mode, emacs
+@cindex input mode, emacs
+@section Emacs Mode
+
+In ``emacs mode'', no input events are send to the terminal.  In this
+mode, you can interact with the terminal buffer just like a regular
+buffer.  However, you are not allowed to change the buffer contents.
+
+@kindex C-c C-e @r{(``semi-char mode'')}
+To switch to ``emacs mode'', press @kbd{C-c C-e} from ``semi-char
+mode''.
+
+@kindex C-c C-k @r{(``emacs mode'')}
+In this mode, @kbd{C-c C-k} kills the terminal program like in
+``semi-char mode''.
+
+@kindex C-c C-j @r{(``emacs mode'')}
+@kindex C-c M-d @r{(``emacs mode'')}
+From ``emacs mode'', you can switch to ``semi-char mode'' with
+@kbd{C-c C-j} and to ``char mode'' with @kbd{C-c M-d}.  In Eshell, the
+command @command{eshell-toggle-direct-send} is remapped to enable
+``char-mode'', which is usually bound to @kbd{C-c M-d}.
+
+@part Part III:@* Advanced Customizations
+
+@node Display
+@cindex display
+@chapter Display
+
+Display is the region you see on the terminal.  The program writes to
+the display and manipulates the text on the display.  The display can
+be of any size.  The cursor is always on the display (though it might
+be invisible sometimes, @pxref{Cursor Types}).
+
+@vindex window-adjust-process-window-size-function
+You can resize the display by resizing the terminal window.  The
+display size is controlled by the Emacs user option
+@code{window-adjust-process-window-size-function}. @xref{Process
+Buffers,,, elisp, GNU Emacs Lisp Reference Manual} for the possible
+values of the user option.
+
+@node Scrollback
+@cindex scrollback
+@chapter Scrollback
+
+When you go too downward on the terminal, the terminal starts to
+``scroll''.  This causes the line at the upper side of the terminal to
+go out of the display and become hidden.  But these line are not
+deleted, they are just put in the scrollback region.
+
+Scrollback region is a region just above the display of the terminal.
+This contains the lines that went out of display due to scrolling up.
+
+Scrollback region is not unlimited by default, to avoid using too much
+memory.  You can change the limit, or remove it altogether.
+
+@vindex eat-term-scrollback-size
+@defopt eat-term-scrollback-size
+This controls the size of scrollback region.  It is expressed in
+character.  If set to @var{size}, Eat won't store more than @var{size}
+characters in the scrollback region.  If set to @code{nil}, the
+scrollback region is unlimited.
+@end defopt
+
+@node Cursor Types
+@cindex cursor types
+@cindex types, cursor
+@cindex changing cursor
+@cindex customizing cursor
+@cindex cursor blinking
+@cindex blinking cursor
+@chapter Cursor Types
+
+In terminal, cursor can be of up to three type: ``visible'',
+``invisible'' and ``very visible''.  ``Visible'' is the default cursor
+type, which is the cursor you usually see in a shell (unless the shell
+changes the cursor type).  ``Invisible'' is, as the name suggests,
+invisible, you can't see it.  ``Very visible'' cursor is a blinking
+cursor, programs use this to help you not lose the cursor.
+
+The cursor type can customized with three user options for the three
+types of cursor.  Each of the user options share the same format.
+
+@vindex eat-default-cursor-type
+@defopt eat-default-cursor-type
+This control the cursor shape of ``visible'' cursor type.
+@end defopt
+
+@vindex eat-invisible-cursor-type
+@defopt eat-invisible-cursor-type
+This control the cursor shape of ``invisible'' cursor type.
+@end defopt
+
+@vindex eat-very-visible-cursor-type
+@defopt eat-very-visible-cursor-type
+This control the cursor shape of ``very visible'' cursor type.  This
+cursor blinks, switching between the default cursor shape and a hollow
+box.
+@end defopt
+
+The value type of these user options is a list.  The list is of form
+(@var{cursor-on} @var{blinking-frequency} @var{cursor-off}).
+@var{blinking-frequency} is the frequency of blinking of cursor.  It
+is a number, controlling how many times the cursor will blink a
+second.  This can also be @code{nil}, this will disable cursor
+blinking.  @var{cursor-on} is the default cursor shape, only this
+shape is shown on the display when blinking is disabled.  This uses
+the same format as Emacs's @code{cursor-type} user option
+(@pxref{Cursor Display,,, emacs, GNU Emacs Manual}).  When
+@var{blinking-frequency} is a number, Eat will consult to the third
+element of the list, @var{cursor-off}, whose format same as
+@var{cursor-on}.  The blinking cursor switches between @var{cursor-on}
+and @var{cursor-off} cursor shape.
+
+@node Mouse Tracking
+@cindex mouse tracking
+@cindex tracking mouse
+@chapter Mouse Tracking
+
+Eat tracks mouse by default, when the program supports mouse.  But
+sometimes, you may want to avoid using mouse, or you might not have a
+mouse at all.  So mouse tracking can be toggled.
+
+@vindex eat-enable-mouse
+@defopt eat-enable-mouse
+This user option controls mouse tracking.  When set to non-@code{nil},
+mouse tracking is enabled.  Set to this to @code{nil} to disable mouse
+tracking.  This is enabled by default.
+@end defopt
+
+@node Clipboard
+@cindex clipboard
+@chapter Clipboard
+
+@cindex yanking
+@findex eat-yank
+@kindex C-y @r{(``semi-char mode'')}
+@findex eat-yank-pop
+@kindex M-y @r{(``semi-char mode'')}
+Just like any other buffer, you can yank text in terminal with
+@kbd{C-y} (bound to @command{eat-yank}) or @kbd{M-y} (bound to
+@command{eat-yank-pop}) in ``semi-char mode''.
+
+@cindex clipboard integration
+Programs can also request to the terminal to kill (@pxref{Killing,,,
+emacs, GNU Emacs Manual}) something.  It is up to Eat whether the
+request will be fulfilled or not.  By default, Eat fulfills the
+request and kills the text.  This can sometimes be annoying, when the
+program automatically kills text without user interaction.  This
+killing can be configured with the following user option:
+
+@vindex eat-enable-kill-from-terminal
+@defopt eat-enable-kill-from-terminal
+This controls killing texts from terminal.  When set to
+non-@code{nil}, killing something from terminal add the text to
+Emacs's kill ring (@pxref{Kill Ring,,, emacs, GNU Emacs Manual}).
+This is enabled by default.
+@end defopt
+
+Programs can also request the text in kill ring.  Again, this is up to
+Eat whether the request will be fulfilled or not.  You can customize
+the following user option to configure this:
+
+@vindex eat-enable-yank-to-terminal
+@defopt eat-enable-yank-to-terminal
+This controls sending kill ring texts to terminal.  When set to
+non-@code{nil}, programs can receive the kill ring contents.  This is
+disabled by default for security reasons.
+@end defopt
+
+@node Colors
+@cindex colors
+@cindex customizing colors
+@chapter Colors
+
+Eat can show more than 16 million colors (16,777,216 colors exactly).
+Eat has also a palette of 256 colors, which is more than enough for
+most applications.  Programs usually use this color palette.  Each of
+these 256 colors can customized.
+
+There are 256 faces for the 256 colors, one face for each color.  They
+are named like @code{eat-term-color-@var{n}}, which corresponds to
+color @var{n}, and @var{n} can be any number between 0 and 255
+(inclusive).  For example, color 42 is can be changed by customizing
+@code{eat-term-color-42}.
+
+The foreground attribute contains the color value to use for the
+corresponding color.  Other attributes are currently ignored and
+reserved for future changes.
+
+@cindex color aliases
+@cindex face aliases
+@cindex aliases, face
+@cindex aliases, color
+Each of the first 16 colors, from @code{eat-term-color-0} to
+@code{eat-term-color-15} also have a alias.  They are respectively
+@code{eat-term-color-black},
+@code{eat-term-color-red},
+@code{eat-term-color-green},
+@code{eat-term-color-yellow},
+@code{eat-term-color-blue},
+@code{eat-term-color-magenta},
+@code{eat-term-color-cyan},
+@code{eat-term-color-white},
+@code{eat-term-color-bright-black},
+@code{eat-term-color-bright-red},
+@code{eat-term-color-bright-green},
+@code{eat-term-color-bright-yellow},
+@code{eat-term-color-bright-blue},
+@code{eat-term-color-bright-magenta},
+@code{eat-term-color-bright-cyan}
+and @code{eat-term-color-bright-white}.
+
+Eat also supports 24-bit colors, or so called ``truecolor''.  Programs
+like Emacs can give a RGB triplet to use as the color of some text.
+As the programs directly specify the color in this case, you can't
+customize these color.  But you may configure the program sending the
+color codes.
+
+@cindex color advertisement
+@cindex advertising colors
+Eat doesn't always advertise color support depending on the display
+Eat is running.  For example, if you are on a Linux console which
+supports only eight colors, Eat will advertise eight color support to
+the programs, while on graphical displays with 24-bit color support,
+Eat will report 24-bit color support.  This is because Eat supports
+more colors, the display doesn't always support them.
+
+@vindex TERM
+@cindex @env{TERM} environment variable
+@cindex environment variable, @env{TERM}
+Eat does the trick by setting the @env{TERM} environment variable of
+the program.  The value of @env{TERM} depends on the number of the
+available colors on the display.  This environment variable is
+controlled by the following user option:
+
+@vindex eat-term-name
+@defopt eat-term-name
+The value of @env{TERM} environment variable as a string.  The value
+can also be a function taking no arguments, that function should
+return a string which used as the value of @env{TERM}.  The default
+value is @code{eat-term-get-suitable-term-name}, which is responsible
+for the behavior described above.
+@end defopt
+
+@node Fonts
+@cindex fonts
+@chapter Fonts
+
+Programs may request the terminal to change the text font.  It can
+change text weight, use italic text, or even change the font family
+altogether.
+
+@cindex bold text
+@cindex text, bold
+@vindex eat-term-bold
+Programs may request the terminal to show some text bolder than
+normal.  Bold text uses the face @code{eat-term-bold}.
+
+@cindex faint text
+@cindex text, faint
+@vindex eat-term-bold
+Programs may also request the terminal to show some text fainter than
+normal.  Faint text uses the face @code{eat-term-faint}.
+
+@cindex italic text
+@cindex slant text
+@cindex text, italic
+@cindex text, slant
+@vindex eat-term-italic
+Programs may request the terminal to show italic text too.  Italic
+text uses the customizable face @code{eat-term-faint}.
+
+@cindex font family
+@cindex text, font family
+The number of available fonts is ten.  Most of the programs doesn't
+change the font.  Following many other terminal emulator, Eat actually
+uses the same font, the default font, regardless of the font requested
+by the program, by default.
+
+@cindex customizing font families
+There are ten faces for ten fonts, one face for each.  They are named
+like @code{eat-term-font-@var{n}}, which corresponds to color @var{n},
+and @var{n} can be any number between 0 and 9 (inclusive).  For
+example, the font 6 is can be changed by customizing
+@code{eat-term-font-6}.  Font 0 is the default font.
+
+@node Blinking Text
+@cindex blinking text
+@cindex text, blinking
+@chapter Blinking Text
+
+Programs can request the terminal to blink some text.  This helps to
+get user attention.  But however, often this annoying to many people
+and also has accessiblity problems.  So this is disabled by default.
+
+@vindex eat-enable-blinking-text
+@defopt eat-enable-blinking-text
+This controls the blinking of text with blink attribute.  When set to
+non-@code{nil}, Eat arranges that text with blink attribute will
+blink at a certain interval.
+@end defopt
+
+@findex eat-blink-mode
+You can toggle blinking temporarily by toggle the buffer-local minor
+mode @command{eat-blink-mode}.  This is only effective in the buffer
+where the mode is toggled.
+
+By default, @code{eat-enable-blinking-text} is set to @code{nil}.
+This disables text blinking and causes the text with blink attribute
+to be displayed in inverse video (swapped foreground and background).
+
+@vindex eat-term-slow-blink
+@vindex eat-term-fast-blink
+Programs may also request to blink some text more rapidly that other
+blinking text.  When blinking is disabled, the face
+@code{eat-term-slow-blink} is used for slowly blinking text, and
+@code{eat-term-fast-blink} for rapidly blinking text.
+
+When blinking is enabled, by setting @code{eat-enable-blinking-text}
+to non-@code{nil} value, the following user options can be customized
+to change the rate of blinking:
+
+@vindex eat-slow-blink-frequency
+@defopt eat-slow-blink-frequency
+The blinking rate of slowly blinking text.  When set to a number N,
+it causes slowly blinking text to blink N times a second.  The value
+can also be a floating point number.  The default value is 2, meaning
+that the slowing text will blink two times a second.
+@end defopt
+
+@vindex eat-fast-blink-frequency
+@defopt eat-fast-blink-frequency
+The blinking rate of rapidly blinking text.  When set to a number N,
+it causes rapidly blinking text to blink N times a second.  The value
+can also be a floating point number as well.  The default value is 3,
+meaning that the slowing text will blink three times a second.
+@end defopt
+
+@node Performance Tuning
+@cindex performance tuning
+@cindex tuning performance
+@chapter Performance Tuning
+
+Eat tries to be as fast as possible.  So Eat employs some techniques
+to maximize performance.
+
+Some program choke and hang when given too much input at once.  So Eat
+divides large input to smaller chunks and sends the chunks one at a
+time.  The maximum size of a input chunk is controlled by
+@code{eat-input-chunk-size}.
+
+@vindex eat-input-chunk-size
+@defopt eat-input-chunk-size
+The value is a integer.  Eat treat input larger than this many
+character as large and breaks it into chunks of at most this size
+before sending the input.
+@end defopt
+
+@cindex flickering
+@cindex reason behind flickering
+@cindex cause of flickering
+Programs also break large output into smaller chunks before sending
+it to the terminal, for same reason.  Eat doesn't suffer from the
+problem, but there isn't any standard way to inform programs about
+this, and usually there are other obstructions sending large amount of
+data at once.  These small chunks create another problem for Eat,
+flickering.  When updating the whole display, the output is usually
+pretty large and the programs break them into smaller chunks.  Each of
+the chunks update the display partially.  After receiving the last
+chunk, the update is complete and the display can be updated.  But it
+is impossible for Eat to guess the last chunk, so Eat has to redisplay
+or update the display after receiving each chunk.  This is the reason
+why sometimes the terminal shows some old contents and some new.  This
+only lasts for a fraction of a second until the next chunk is received
+and processed.  This is flickering.  This also degrades performance,
+because redisplay is an expensive process and takes some time.
+
+@cindex fixing flickering
+@cindex flickering fix
+@cindex latency
+Fixing the flickering completely is not possible.  Eat tries to
+decrease flickering by deferring redisplay.  After receiving a chunk,
+Eat waits for a tiny fraction of a second.  If another chunk arrives
+within the time, the redisplay is postponed.  Then Eat waits for the
+same amount of time and this goes on.  When timeout occurs, Eat
+processing the output and displays the output.  This causes a small
+latency between output arrive and redisplay, but this is usually not
+long enough for human eyes to catch it.  This waiting time can be
+configured with the following user option:
+
+@vindex eat-minimum-latency
+@defopt eat-minimum-latency
+The value is the time in seconds to wait for the next chunk to arrive.
+This is the minimum latency between the first chunk after a redisplay
+and the next redisplay.  For example, if you press @kbd{@key{RET}} in
+an empty Bash prompt, the next prompt won't appear before this much
+time.
+
+You should set the time to something comfortable for you.  You can
+also set this to zero is disable waiting and showing the output
+instantly, but this would likely cause a lot of flickering.
+@end defopt
+
+However, this waiting raises another problem.  What if you execute the
+POSIX command @samp{yes} in the terminal?  It will write infinite
+``y''s in the terminal without any delay between them anywhere.  Eat
+will wait indefinitely for a delay between two chunks, which will
+never happen, unless the program is executed remotely and the
+connection is slow enough.  So Eat has a limit for waiting, the
+display will be always be updated after this time.  This limit also
+customizable:
+
+@vindex eat-maximum-latency
+@defopt eat-maximum-latency
+The value is the time in seconds to wait at most for chunk.  In case
+of large burst of output, redisplay is never deferred more than this
+many seconds, and cause a latency of up to this many seconds.
+
+You should set the time to something comfortable for you.  You can
+also set this to zero is disable waiting and showing the output
+instantly, but this would likely cause a lot of flickering.
+@end defopt
+
+The user option described in this chapter have reasonable default
+values, but they may change anytime.
+
+@part Part IV:@* Recovering from Problems
+
+@node Common Problems
+@cindex common problems
+@cindex problem, common
+@chapter Common Problems
+
+This chapter describe how to recognize and handle situations in which
+Eat does something unexpected, such as hangs, garbled text, etc.
+
+@menu
+* Not Recognized::      The program can't recognize Eat.
+* Garbled Text::        When you get garbage on your terminal.
+* Not Responding::      What to do if Eat is unresponsive.
+* Signaled an Error::   The worst and the most unlikely bug.
+* Bugs in Manual::      What if there are problems in this manual?
+@end menu
+
+@node Not Recognized
+@cindex not recognized
+@cindex problem, not recognized
+@cindex terminal not recognized
+@cindex problem, terminal not recognized
+@section Terminal Not Recognized
+
+If your program says that it can't recognize the terminal, probably
+the @env{TERM} environment has a wrong value.
+
+Check the value of @env{TERM}, if it's not set to something like
+@samp{eat-...}, check the user option @code{eat-term-name}.  If that's
+correct that your shell might be changing the @env{TERM} environment
+variable.  If @code{eat-term-name} isn't correct, customize to a
+suitable value and try again, your problem should be fixed.
+
+If @env{TERM} has the correct value, then probably the Terminfo
+entries of Eat are missing.  This can happen if you manually install
+Eat.  Check that whether the values of the environment value
+@env{TERM} and the user option @code{eat-term-terminfo-directory}
+match.  If they match, customize @code{eat-term-terminfo-directory} to
+the directory that contains the Terminfo database, the program should
+now recognize Eat.  If they don't match, then your shell is probably
+responsible for the problem.
+
+@node Garbled Text
+@cindex garbled text
+@cindex problem, garbled text
+@cindex problem, text garbled
+@section Garbled Text on Terminal
+
+If the text on the terminal looks wrong, first check out the value of
+@env{TERM}.  Usually @env{TERM} has a wrong value set, making programs
+send invalid escape sequences.
+
+First, @pxref{Not Recognized}; the problem is most likely because the
+problem doesn't recognize Eat, and it stays silent instead of
+reporting that.
+
+If the problem isn't resolved after following the instructions in the
+previous section, may be your program is blindly assuming that the
+terminal is XTerm-compatible.  If so, what you are seeing is the
+current state of ``XTerm-compliance''.  Though it's not really a bug,
+we definite want to know what's problem so that we can fix it.
+@xref{Reporting Bugs} for instructions on sending bug reports or
+feature request.
+
+The other potential reason is that Eat is not working.  This is
+definitely a bug, so please report it.
+
+@node Not Responding
+@cindex not responding, eat
+@cindex not responding, emacs
+@cindex eat not responding
+@cindex emacs not responding
+@cindex problem, eat not responding
+@cindex problem, emacs not responding
+@cindex problem, not responding, eat
+@cindex problem, not responding, emacs
+@section Emacs or Eat Not Responding
+
+If you run something that outputs huge amount of data, your Emacs may
+not respond, and even quitting may not work.  Quitting doesn't work
+while doing something terminal related (output processing, for
+example), and that's intentional, because quitting would mess up the
+terminal.
+
+The best way to fix it is to stop the program, so that Eat is not
+overloaded.  To avoid the problem in future, it is recommended to run
+those programs in faster terminals like bare Eshell (i.e. without
+Eat-Eshell), Comint, or external terminal emulators.
+
+@node Signaled an Error
+@cindex signaled an error
+@cindex eat signaled an error
+@cindex problem, signaled an error
+@cindex problem, eat signaled an error
+@section Eat Signaled an Error
+
+The worst thing that happen is that Eat might signal an error.  It is
+the worst thing possible, because it messes up the terminal, and also
+a security hole.  Fortunately, this is very rare.  If you ever find
+any such bug, you should report the bug (@pxref{Reporting Bugs}) as
+soon as possible with as much information as possible.
+
+@findex eat-reset
+Once the error signaled, your best option is to delete the terminal
+and start a new one.  But if you don't want to delete the terminal,
+you can try invoking the command @command{reset} from your shell.  If
+for some reason you can't do that, invoke the Emacs command
+@command{eat-reset}.  This will reset most of the terminal state and
+give you a clean terminal to work with.  However, it mayn't work if
+you're really unlucky, in that case deleting the terminal and starting
+a new one is your only option.
+
+@node Bugs in Manual
+@cindex bugs in manual
+@cindex typos in manual
+@cindex bugs, manual
+@cindex typos, manual
+@cindex manual, bugs
+@cindex manual, typos
+@cindex problems, bugs in manual
+@cindex problems, typos in manual
+@cindex problems, bugs, manual
+@cindex problems, typos, manual
+@cindex problems, manual, bugs
+@cindex problems, manual, typos
+@section Bugs in Manual
+
+Human makes mistake, and we are no exceptions.  But we are trying hard
+to improve Eat and it's manual.
+
+If you don't understand something even after a careful rereading,
+that's a bug.
+
+If you find anything unclear in this manual, that's a bug.
+
+This manual's job is make everything clear, so failing to do that
+indicates a bug.
+
+If the built-in documentation and this manual don't agree, one of them
+must be wrong, and that's a bug.
+
+If you Eat doesn't behave as this manual describes, that's a bug.
+
+If you find any typing mistakes, that's a bug.
+
+If you find a bug, please report it.  @xref{Reporting Bugs} for
+instruction on how to report it.
+
+@node Reporting Bugs
+@cindex reporting bugs
+@cindex bug reporting
+@cindex problem, reporting
+@chapter Reporting Bugs
+
+We welcome bug reports and feature request.  If you think you have
+found a bug, please report it.  If you're doubt, please send it
+anyway.  We can't promise that we'll fix the bug or implement your
+feature idea, or always agree that it's a bug, but we always want to
+hear from you.  Please report bugs at
+@url{https://codeberg.org/akib/emacs-eat/issues/new}.  You may send
+the bug report by emailing to the maintain
+(@kbd{M-x describe-package RET eat RET} would show the email address),
+but we prefer the former method, since the report is visible to
+everyone immediately.
+
+The most important principle in reporting a bug is to report
+@emph{facts}.  Hypotheses and verbal descriptions are useful when they
+are more guesses, but in no way substitute for detailed raw data.  You
+are encouraged to send you finding about bug, but please make sure to
+send the raw data needed to reproduce the bug.
+
+For bug reports, please try to reproduce the bug with @samp{emacs -Q}.
+This will disable loading your Emacs configuration, ruling out the
+potential bugs in your customizations.  Please include enough
+information for us to reproduce the bug with @samp{emacs -Q}, so that
+we have (or can get) enough information about the bug to fix it.  Some
+bugs are hard to reproduce with @samp{emacs -Q}, and some are not
+easily reproducible at all, in that case please give us the as much
+information as possible about Emacs configuration.  Generally
+speaking, enough information includes (but not limited to):
+
+@itemize @bullet
+@item
+A description of the bug.
+
+@item
+The version of Eat you're running.
+(@kbd{M-x describe-package RET eat RET} would show the version.)
+
+@item
+The version of Emacs you're running.
+
+@item
+Your Eat configuration, precisely.
+
+@item
+If you didn't or can't reproduce the bug with @code{emacs -Q}, as much
+information as possible about Emacs configuration.
+
+@item
+Precisely what you did.
+
+@item
+Trace output, if you can generate it.  (@xref{Tracing the Terminal}
+for instruction to generate it.)
+
+@item
+Hardware and operating system names and versions.
+
+@item
+Anything else that you think would be helpful.
+@end itemize
+
+When in doubt whether to include something or not, please include it.
+It is better to include many useless information than to leave out
+something useful.
+
+It is critical to send enough information to reproduce the bug.  What
+is not critical to ``narrow down'' the example to the smallest
+possible -- anything that reproduces the bug will suffice.  (Of
+course, if you like doing experiments, the smaller the example, the
+better.)
+
+@node Tracing the Terminal
+@cindex tracing the terminal
+@cindex terminal tracing
+@cindex terminal recording
+@chapter Tracing the Terminal
+
+When you run into a bug and want to report it, you'll want to trace
+the terminal.  Tracing means recording all the terminal activity,
+including creation, output, resizing and deleting.
+
+@findex eat-trace-mode
+To enable tracing, enable the global minor mode
+@command{eat-trace-mode}.  This will trace all new terminals,
+including the terminal created inside Eshell.
+
+Trace output for each command will be output in a buffer named
+@samp{*eat-trace @var{buffer-name}*: @var{command}}, where
+@var{buffer-name} is the buffer showing the terminal, and
+@var{command} is the command run in the terminal.
+
+Only the terminals created after the trace mode is enabled are traced.
+So if you don't have the mode enabled when you have found a bug,
+tracing can't give you any information (as tracing is disabled,
+nothing has been recorded).
+
+While submitting bug reports, please include the whole output in the
+trace output buffer.  This contains many crucial information required
+to reproduce your bug.
+
+@findex eat-trace-replay
+You can replay the terminal by executing the command
+@command{eat-trace-replay} is the trace output buffer.  You can use
+the key @kbd{n} or the key @kbd{@key{down}} to show the next frame.
+This is not intended for ordinary users, it's documented here only to
+help you debug Eat.  You mustn't rely on the behavior of this
+functionality to do anything else.
+
+@part Part V:@* Appendices
+
+@node GNU General Public License
+@appendix GNU General Public License
+
+@include gpl.texi
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+
+@include fdl.texi
+
+@node Index
+@appendix Index
+
+@printindex cp
+
+@bye
diff --git a/eat.ti b/eat.ti
new file mode 100644
index 0000000000..7f80e0dc40
--- /dev/null
+++ b/eat.ti
@@ -0,0 +1,206 @@
+# The code here is forced by the interface, and is not subject to
+# copyright, constituting the only possible expression of the
+# algorithm in this format.
+#
+# When updating this file, files in e/ should be regenerated by
+# running in "make" or "make terminfo" here.
+
+eat-mono|Emacs Eat without colors,
+  cols#80,
+  lines#24,
+  am,
+  clear=\e[2J,
+  cr=\r,
+  bel=^G,
+  home=\e[H,
+  cub1=\b,
+  cuf1=\e[C,
+  cuu1=\e[A,
+  cud1=^K,
+  ind=\n,
+  indn=\e[%p1%dS,
+  ri=\eM,
+  rin=\e[%p1%dT,
+  nel=\eE,
+  cup=\e[%i%p1%d;%p2%dH,
+  hpa=\e[%i%p1%dG,
+  vpa=\e[%i%p1%dd,
+  cub=\e[%p1%dD,
+  cuf=\e[%p1%dC,
+  cuu=\e[%p1%dA,
+  cud=\e[%p1%dB,
+  smcup=\e[?1049h,
+  rmcup=\e[?1049l,
+  el=\e[K,
+  el1=\e[1K,
+  ed=\e[J,
+  Ed=\e[J,
+  il1=\e[L,
+  il=\e[%p1%dL,
+  dl1=\e[M,
+  dl=\e[%p1%dM,
+  csr=\e[%i%p1%d;%p2%dr,
+  sc=\e7,
+  rc=\e8,
+  smir=\e[4h,
+  rmir=\e[4l,
+# ich1=\e[@,
+  ich=\e[%p1%d@,
+  mir,
+  dch1=\e[P,
+  dch=\e[%p1%dP,
+  ech=\e[%p1%dX,
+  smso=\e[7m,
+  rmso=\e[27m,
+  smul=\e[4m,
+  rmul=\e[24m,
+  sitm=\e[3m,
+  ritm=\e[23m,
+  blink=\e[5m,
+  bold=\e[1m,
+  dim=\e[2m,
+  invis=\e[8m,
+  rev=\e[7m,
+  sgr0=\e(B\e[m,
+  sgr=%?%p9%t\e(0%e\e(B%;
+      \e[0%?%p6%t;1%;
+          %?%p5%t;2%;
+          %?%p2%t;4%;
+          %?%p1%p3%|%t;7%;
+          %?%p4%t;5%;
+          %?%p7%t;8%;m,
+  msgr,
+  cvvis=\e[?12;25h,
+  civis=\e[?25l,
+  cnorm=\e[?12l\e[?25h,
+  smkx=\e[?1h,
+  rmkx=\e[?1l,
+  ht=\t,
+  cbt=\e[Z,
+  it#8,
+  rs1=\e\\\ec,
+  hs,
+  tsl=\e]2;,
+  fsl=\e\\,
+  dsl=\e]2;\e\\,
+  xenl,
+  acsc=++\,\,--..00``aaffggiihhjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+  smacs=\e(0,
+  rmacs=\e(B,
+  npc,
+  rep=%p1%c\E[%p2%{1}%-%db,
+  u6=\e[%i%d;%dR,
+  u7=\e[6n,
+  smam=\e[?7h,
+  rmam=\e[?7l,
+  smxx=\e[9m,
+  rmxx=\e[29m,
+  kbs=^?,
+  kcuu1=\eOA,
+  kri=\e[1;2A,
+  kcud1=\eOB,
+  kind=\e[1;2B,
+  kcuf1=\eOC,
+  kRIT=\e[1;2C,
+  kcub1=\eOD,
+  kLFT=\e[1;2D,
+  kich1=\e[2~,
+  kIC=\e[2;2~,
+  kdch1=\e[3~,
+  kDC=\e[3;2~,
+  khome=\eOH,
+  kHOM=\e[1;2H,
+  kend=\eOF,
+  kEND=\e[1;2F,
+  kpp=\e[5~,
+  kPRV=\e[5;2~,
+  knp=\e[6~,
+  kNXT=\e[6;2~,
+  kf1=\eOP,
+  kf2=\eOQ,
+  kf3=\eOR,
+  kf4=\eOS,
+  kf5=\e[15~,
+  kf6=\e[17~,
+  kf7=\e[18~,
+  kf8=\e[19~,
+  kf9=\e[20~,
+  kf10=\e[21~,
+  kf11=\e[23~,
+  kf12=\e[24~,
+  kf13=\e[1;2P,
+  kf14=\e[1;2Q,
+  kf15=\e[1;2R,
+  kf16=\e[1;2S,
+  kf17=\e[15;2~,
+  kf18=\e[17;2~,
+  kf19=\e[18;2~,
+  kf20=\e[19;2~,
+  kf21=\e[20;2~,
+  kf22=\e[21;2~,
+  kf23=\e[23;2~,
+  kf24=\e[24;2~,
+  kf25=\e[1;5P,
+  kf26=\e[1;5Q,
+  kf27=\e[1;5R,
+  kf28=\e[1;5S,
+  kf29=\e[15;5~,
+  kf30=\e[17;5~,
+  kf31=\e[18;5~,
+  kf32=\e[19;5~,
+  kf33=\e[20;5~,
+  kf34=\e[21;5~,
+  kf35=\e[23;5~,
+  kf36=\e[24;5~,
+  kf37=\e[1;6P,
+  kf38=\e[1;6Q,
+  kf39=\e[1;6R,
+  kf40=\e[1;6S,
+  kf41=\e[15;6~,
+  kf42=\e[17;6~,
+  kf43=\e[18;6~,
+  kf44=\e[19;6~,
+  kf45=\e[20;6~,
+  kf46=\e[21;6~,
+  kf47=\e[23;6~,
+  kf48=\e[24;6~,
+  kf49=\e[1;3P,
+  kf50=\e[1;3Q,
+  kf51=\e[1;3R,
+  kf52=\e[1;3S,
+  kf53=\e[15;3~,
+  kf54=\e[17;3~,
+  kf55=\e[18;3~,
+  kf56=\e[19;3~,
+  kf57=\e[20;3~,
+  kf58=\e[21;3~,
+  kf59=\e[23;3~,
+  kf60=\e[24;3~,
+  kf61=\e[1;4P,
+  kf62=\e[1;4Q,
+  kf63=\e[1;4R,
+  kmous=\e[M,
+
+eat-color|Emacs Eat with eight colors,
+  use=eat-mono,
+  colors#0x8,
+  pairs#0x40,
+  bce,
+  op=\e[39;49m,
+  setab=\e[4%p1%dm,
+  setaf=\e[3%p1%dm,
+  setb=\e[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+  setf=\e[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+
+eat-256color|Emacs Eat with 256 colors,
+  use=eat-color,
+  colors#0x100,
+  pairs#0x10000,
+  setab=\e[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
+  setaf=\e[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
+  setb@,
+  setf@,
+
+eat-truecolor|Emacs Eat with truecolor,
+  use=eat-256color,
+  Tc,
diff --git a/fdl.texi b/fdl.texi
new file mode 100644
index 0000000000..eaf3da0e92
--- /dev/null
+++ b/fdl.texi
@@ -0,0 +1,505 @@
+@c The GNU Free Documentation License.
+@center Version 1.3, 3 November 2008
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, 
Inc.
+@uref{https://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The ``Document'', below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as ``you''.  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, La@TeX{} input
+format, SGML or XML using a publicly available
+DTD, and standard-conforming simple HTML,
+PostScript or PDF designed for human modification.  Examples
+of transparent image formats include PNG, XCF and
+JPG@.  Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, SGML or
+XML for which the DTD and/or processing tools are
+not generally available, and the machine-generated HTML,
+PostScript or PDF produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The ``publisher'' means any person or entity that distributes copies
+of the Document to the public.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.)  To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document).  You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page.  If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on.  These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles.  Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''.  Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''.  You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+@uref{https://www.gnu.org/licenses/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+@item
+RELICENSING
+
+``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
+site means any set of copyrightable works thus published on the MMC
+site.
+
+``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+``Incorporate'' means to publish or republish a Document, in whole or
+in part, as part of another Document.
+
+An MMC is ``eligible for relicensing'' if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole
+or in part into the MMC, (1) had no cover texts or invariant sections,
+and (2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+@end enumerate
+
+@page
+@heading ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+  Copyright (C)  @var{year}  @var{your name}.
+  Permission is granted to copy, distribute and/or modify this document
+  under the terms of the GNU Free Documentation License, Version 1.3
+  or any later version published by the Free Software Foundation;
+  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+  Texts.  A copy of the license is included in the section entitled ``GNU
+  Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with@dots{}Texts.''@: line with this:
+
+@smallexample
+@group
+    with the Invariant Sections being @var{list their titles}, with
+    the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+    being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
diff --git a/gitlog-to-changelog b/gitlog-to-changelog
new file mode 100755
index 0000000000..82d9f97336
--- /dev/null
+++ b/gitlog-to-changelog
@@ -0,0 +1,516 @@
+#!/bin/sh
+#! -*-perl-*-
+
+# Convert git log output to ChangeLog format.
+
+# Copyright (C) 2008-2022 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+#
+# Written by Jim Meyering
+
+# This is a prologue that allows to run a perl script as an executable
+# on systems that are compliant to a POSIX version before POSIX:2017.
+# On such systems, the usual invocation of an executable through execlp()
+# or execvp() fails with ENOEXEC if it is a script that does not start
+# with a #! line.  The script interpreter mentioned in the #! line has
+# to be /bin/sh, because on GuixSD systems that is the only program that
+# has a fixed file name.  The second line is essential for perl and is
+# also useful for editing this file in Emacs.  The next two lines below
+# are valid code in both sh and perl.  When executed by sh, they re-execute
+# the script through the perl program found in $PATH.  The '-x' option
+# is essential as well; without it, perl would re-execute the script
+# through /bin/sh.  When executed by perl, the next two lines are a no-op.
+eval 'exec perl -wSx "$0" "$@"'
+     if 0;
+
+my $VERSION = '2022-01-27 18:49'; # UTC
+# The definition above must lie within the first 8 lines in order
+# for the Emacs time-stamp write hook (at end) to update it.
+# If you change this file with Emacs, please let the write hook
+# do its job.  Otherwise, update this string manually.
+
+use strict;
+use warnings;
+use Getopt::Long;
+use POSIX qw(strftime);
+
+(my $ME = $0) =~ s|.*/||;
+
+# use File::Coda; # https://meyering.net/code/Coda/
+END {
+  defined fileno STDOUT or return;
+  close STDOUT and return;
+  warn "$ME: failed to close standard output: $!\n";
+  $? ||= 1;
+}
+
+sub usage ($)
+{
+  my ($exit_code) = @_;
+  my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
+  if ($exit_code != 0)
+    {
+      print $STREAM "Try '$ME --help' for more information.\n";
+    }
+  else
+    {
+      print $STREAM <<EOF;
+Usage: $ME [OPTIONS] [ARGS]
+
+Convert git log output to ChangeLog format.  If present, any ARGS
+are passed to "git log".  To avoid ARGS being parsed as options to
+$ME, they may be preceded by '--'.
+
+OPTIONS:
+
+   --amend=FILE FILE maps from an SHA1 to perl code (i.e., s/old/new/) that
+                  makes a change to SHA1's commit log text or metadata.
+   --append-dot append a dot to the first line of each commit message if
+                  there is no other punctuation or blank at the end.
+   --no-cluster never cluster commit messages under the same date/author
+                  header; the default is to cluster adjacent commit messages
+                  if their headers are the same and neither commit message
+                  contains multiple paragraphs.
+   --srcdir=DIR the root of the source tree, from which the .git/
+                  directory can be derived.
+   --since=DATE convert only the logs since DATE;
+                  the default is to convert all log entries.
+   --until=DATE convert only the logs older than DATE.
+   --ignore-matching=PAT ignore commit messages whose first lines match PAT.
+   --ignore-line=PAT ignore lines of commit messages that match PAT.
+   --format=FMT set format string for commit subject and body;
+                  see 'man git-log' for the list of format metacharacters;
+                  the default is '%s%n%b%n'
+   --strip-tab  remove one additional leading TAB from commit message lines.
+   --strip-cherry-pick  remove data inserted by "git cherry-pick";
+                  this includes the "cherry picked from commit ..." line,
+                  and the possible final "Conflicts:" paragraph.
+   --help       display this help and exit
+   --version    output version information and exit
+
+EXAMPLE:
+
+  $ME --since=2008-01-01 > ChangeLog
+  $ME -- -n 5 foo > last-5-commits-to-branch-foo
+
+SPECIAL SYNTAX:
+
+The following types of strings are interpreted specially when they appear
+at the beginning of a log message line.  They are not copied to the output.
+
+  Copyright-paperwork-exempt: Yes
+    Append the "(tiny change)" notation to the usual "date name email"
+    ChangeLog header to mark a change that does not require a copyright
+    assignment.
+  Co-authored-by: Joe User <user\@example.com>
+    List the specified name and email address on a second
+    ChangeLog header, denoting a co-author.
+  Signed-off-by: Joe User <user\@example.com>
+    These lines are simply elided.
+
+In a FILE specified via --amend, comment lines (starting with "#") are ignored.
+FILE must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1 (alone on
+a line) referring to a commit in the current project, and CODE refers to one
+or more consecutive lines of Perl code.  Pairs must be separated by one or
+more blank line.
+
+Here is sample input for use with --amend=FILE, from coreutils:
+
+3a169f4c5d9159283548178668d2fae6fced3030
+# fix typo in title:
+s/all tile types/all file types/
+
+1379ed974f1fa39b12e2ffab18b3f7a607082202
+# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself.
+# Change the author to be Paul.  Note the escaped "@":
+s,Jim .*>,Paul Eggert <eggert\\\@cs.ucla.edu>,
+
+EOF
+    }
+  exit $exit_code;
+}
+
+# If the string $S is a well-behaved file name, simply return it.
+# If it contains white space, quotes, etc., quote it, and return the new 
string.
+sub shell_quote($)
+{
+  my ($s) = @_;
+  if ($s =~ m![^\w+/.,-]!)
+    {
+      # Convert each single quote to '\''
+      $s =~ s/\'/\'\\\'\'/g;
+      # Then single quote the string.
+      $s = "'$s'";
+    }
+  return $s;
+}
+
+sub quoted_cmd(@)
+{
+  return join (' ', map {shell_quote $_} @_);
+}
+
+# Parse file F.
+# Comment lines (starting with "#") are ignored.
+# F must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1
+# (alone on a line) referring to a commit in the current project, and
+# CODE refers to one or more consecutive lines of Perl code.
+# Pairs must be separated by one or more blank line.
+sub parse_amend_file($)
+{
+  my ($f) = @_;
+
+  open F, '<', $f
+    or die "$ME: $f: failed to open for reading: $!\n";
+
+  my $fail;
+  my $h = {};
+  my $in_code = 0;
+  my $sha;
+  while (defined (my $line = <F>))
+    {
+      $line =~ /^\#/
+        and next;
+      chomp $line;
+      $line eq ''
+        and $in_code = 0, next;
+
+      if (!$in_code)
+        {
+          $line =~ /^([[:xdigit:]]{40})$/
+            or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"),
+              $fail = 1, next;
+          $sha = lc $1;
+          $in_code = 1;
+          exists $h->{$sha}
+            and (warn "$ME: $f:$.: duplicate SHA1\n"),
+              $fail = 1, next;
+        }
+      else
+        {
+          $h->{$sha} ||= '';
+          $h->{$sha} .= "$line\n";
+        }
+    }
+  close F;
+
+  $fail
+    and exit 1;
+
+  return $h;
+}
+
+# git_dir_option $SRCDIR
+#
+# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR
+# is undef).  Return as a list (0 or 1 element).
+sub git_dir_option($)
+{
+  my ($srcdir) = @_;
+  my @res = ();
+  if (defined $srcdir)
+    {
+      my $qdir = shell_quote $srcdir;
+      my $cmd = "cd $qdir && git rev-parse --show-toplevel";
+      my $qcmd = shell_quote $cmd;
+      my $git_dir = qx($cmd);
+      defined $git_dir
+        or die "$ME: cannot run $qcmd: $!\n";
+      $? == 0
+        or die "$ME: $qcmd had unexpected exit code or signal ($?)\n";
+      chomp $git_dir;
+      push @res, "--git-dir=$git_dir/.git";
+    }
+  @res;
+}
+
+{
+  my $since_date;
+  my $until_date;
+  my $format_string = '%s%n%b%n';
+  my $amend_file;
+  my $append_dot = 0;
+  my $cluster = 1;
+  my $ignore_matching;
+  my $ignore_line;
+  my $strip_tab = 0;
+  my $strip_cherry_pick = 0;
+  my $srcdir;
+  GetOptions
+    (
+     help => sub { usage 0 },
+     version => sub { print "$ME version $VERSION\n"; exit },
+     'since=s' => \$since_date,
+     'until=s' => \$until_date,
+     'format=s' => \$format_string,
+     'amend=s' => \$amend_file,
+     'append-dot' => \$append_dot,
+     'cluster!' => \$cluster,
+     'ignore-matching=s' => \$ignore_matching,
+     'ignore-line=s' => \$ignore_line,
+     'strip-tab' => \$strip_tab,
+     'strip-cherry-pick' => \$strip_cherry_pick,
+     'srcdir=s' => \$srcdir,
+    ) or usage 1;
+
+  defined $since_date
+    and unshift @ARGV, "--since=$since_date";
+  defined $until_date
+    and unshift @ARGV, "--until=$until_date";
+
+  # This is a hash that maps an SHA1 to perl code (i.e., s/old/new/)
+  # that makes a correction in the log or attribution of that commit.
+  my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {};
+
+  my @cmd = ('git',
+             git_dir_option $srcdir,
+             qw(log --log-size),
+             '--pretty=format:%H:%ct  %an  <%ae>%n%n'.$format_string, @ARGV);
+  open PIPE, '-|', @cmd
+    or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n"
+            . "(Is your Git too old?  Version 1.5.1 or later is required.)\n");
+
+  my $prev_multi_paragraph;
+  my $prev_date_line = '';
+  my @prev_coauthors = ();
+  my @skipshas = ();
+  while (1)
+    {
+      defined (my $in = <PIPE>)
+        or last;
+      $in =~ /^log size (\d+)$/
+        or die "$ME:$.: Invalid line (expected log size):\n$in";
+      my $log_nbytes = $1;
+
+      my $log;
+      my $n_read = read PIPE, $log, $log_nbytes;
+      $n_read == $log_nbytes
+        or die "$ME:$.: unexpected EOF\n";
+
+      # Extract leading hash.
+      my ($sha, $rest) = split ':', $log, 2;
+      defined $sha
+        or die "$ME:$.: malformed log entry\n";
+      $sha =~ /^[[:xdigit:]]{40}$/
+        or die "$ME:$.: invalid SHA1: $sha\n";
+
+      my $skipflag = 0;
+      if (@skipshas)
+        {
+          foreach(@skipshas)
+            {
+              if ($sha =~ /^$_/)
+                {
+                  $skipflag = $_;
+                  last;
+                }
+            }
+        }
+
+      # If this commit's log requires any transformation, do it now.
+      my $code = $amend_code->{$sha};
+      if (defined $code)
+        {
+          eval 'use Safe';
+          my $s = new Safe;
+          # Put the unpreprocessed entry into "$_".
+          $_ = $rest;
+
+          # Let $code operate on it, safely.
+          my $r = $s->reval("$code")
+            or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n";
+
+          # Note that we've used this entry.
+          delete $amend_code->{$sha};
+
+          # Update $rest upon success.
+          $rest = $_;
+        }
+
+      # Remove lines inserted by "git cherry-pick".
+      if ($strip_cherry_pick)
+        {
+          $rest =~ s/^\s*Conflicts:\n.*//sm;
+          $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m;
+        }
+
+      my @line = split /[ \t]*\n/, $rest;
+      my $author_line = shift @line;
+      defined $author_line
+        or die "$ME:$.: unexpected EOF\n";
+      $author_line =~ /^(\d+)  (.*>)$/
+        or die "$ME:$.: Invalid line "
+          . "(expected date/author/email):\n$author_line\n";
+
+      # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog
+      # `(tiny change)' annotation.
+      my $tiny = (grep 
(/^(?:Copyright-paperwork-exempt|Tiny-change):\s+[Yy]es$/, @line)
+                  ? '  (tiny change)' : '');
+
+      my $date_line = sprintf "%s  %s$tiny\n",
+        strftime ("%Y-%m-%d", localtime ($1)), $2;
+
+      my @coauthors = grep /^Co-authored-by:.*$/, @line;
+      # Omit meta-data lines we've already interpreted.
+      @line = grep !/^(?:Signed-off-by:[ ].*>$
+                       |Co-authored-by:[ ]
+                       |Copyright-paperwork-exempt:[ ]
+                       |Tiny-change:[ ]
+                       )/x, @line;
+
+      # Remove leading and trailing blank lines.
+      if (@line)
+        {
+          while ($line[0] =~ /^\s*$/) { shift @line; }
+          while ($line[$#line] =~ /^\s*$/) { pop @line; }
+        }
+
+      # Handle Emacs gitmerge.el "skipped" commits.
+      # Yes, this should be controlled by an option.  So sue me.
+      if ( grep /^(; )?Merge from /, @line )
+      {
+          my $found = 0;
+          foreach (@line)
+          {
+              if (grep /^The following commit.*skipped:$/, $_)
+              {
+                  $found = 1;
+                  ## Reset at each merge to reduce chance of false matches.
+                  @skipshas = ();
+                  next;
+              }
+              if ($found && $_ =~ /^([[:xdigit:]]{7,}) [^ ]/)
+              {
+                  push ( @skipshas, $1 );
+              }
+          }
+      }
+
+      # Ignore commits that match the --ignore-matching pattern, if specified.
+      if (defined $ignore_matching && @line && $line[0] =~ /$ignore_matching/)
+        {
+          $skipflag = 1;
+        }
+      elsif ($skipflag)
+        {
+          ## Perhaps only warn if a pattern matches more than once?
+          warn "$ME: warning: skipping $sha due to $skipflag\n";
+        }
+
+      if (! $skipflag)
+        {
+          if (defined $ignore_line && @line)
+            {
+              @line = grep ! /$ignore_line/, @line;
+              while ($line[$#line] =~ /^\s*$/) { pop @line; }
+            }
+
+          # Record whether there are two or more paragraphs.
+          my $multi_paragraph = grep /^\s*$/, @line;
+
+          # Format 'Co-authored-by: A U Thor <email@example.com>' lines in
+          # standard multi-author ChangeLog format.
+          for (@coauthors)
+            {
+              s/^Co-authored-by:\s*/\t    /;
+              s/\s*</  </;
+
+              /<.*?@.*\..*>/
+                or warn "$ME: warning: missing email address for "
+                  . substr ($_, 5) . "\n";
+            }
+
+          # If clustering of commit messages has been disabled, if this header
+          # would be different from the previous date/name/etc. header,
+          # or if this or the previous entry consists of two or more 
paragraphs,
+          # then print the header.
+          if ( ! $cluster
+              || $date_line ne $prev_date_line
+              || "@coauthors" ne "@prev_coauthors"
+              || $multi_paragraph
+              || $prev_multi_paragraph)
+            {
+              $prev_date_line eq ''
+                or print "\n";
+              print $date_line;
+              @coauthors
+                and print join ("\n", @coauthors), "\n";
+            }
+          $prev_date_line = $date_line;
+          @prev_coauthors = @coauthors;
+          $prev_multi_paragraph = $multi_paragraph;
+
+          # If there were any lines
+          if (@line == 0)
+            {
+              warn "$ME: warning: empty commit message:\n"
+                   . "  commit $sha\n  $date_line\n";
+            }
+          else
+            {
+              if ($append_dot)
+                {
+                  # If the first line of the message has enough room, then
+                  if (length $line[0] < 72)
+                    {
+                      # append a dot if there is no other punctuation or blank
+                      # at the end.
+                      $line[0] =~ /[[:punct:]\s]$/
+                        or $line[0] .= '.';
+                    }
+                }
+
+              # Remove one additional leading TAB from each line.
+              $strip_tab
+                and map { s/^\t// } @line;
+
+              # Prefix each non-empty line with a TAB.
+              @line = map { length $_ ? "\t$_" : '' } @line;
+
+              print "\n", join ("\n", @line), "\n";
+            }
+        }
+
+      defined ($in = <PIPE>)
+        or last;
+      $in ne "\n"
+        and die "$ME:$.: unexpected line:\n$in";
+    }
+
+  close PIPE
+    or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n";
+  # FIXME-someday: include $PROCESS_STATUS in the diagnostic
+
+  # Complain about any unused entry in the --amend=F specified file.
+  my $fail = 0;
+  foreach my $sha (keys %$amend_code)
+    {
+      warn "$ME:$amend_file: unused entry: $sha\n";
+      $fail = 1;
+    }
+
+  exit $fail;
+}
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-line-limit: 50
+# time-stamp-start: "my $VERSION = '"
+# time-stamp-format: "%:y-%02m-%02d %02H:%02M"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "'; # UTC"
+# End:
diff --git a/gpl.texi b/gpl.texi
new file mode 100644
index 0000000000..c007dc0696
--- /dev/null
+++ b/gpl.texi
@@ -0,0 +1,717 @@
+@c The GNU General Public License.
+@center Version 3, 29 June 2007
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2007 Free Software Foundation, Inc. 
@url{https://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+@end display
+
+@heading Preamble
+
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom
+to share and change all versions of a program---to make sure it remains
+free software for all its users.  We, the Free Software Foundation,
+use the GNU General Public License for most of our software; it
+applies also to any other work released this way by its authors.  You
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you
+have certain responsibilities if you distribute copies of the
+software, or if you modify it: responsibilities to respect the freedom
+of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too,
+receive or can get the source code.  And you must show them these
+terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the
+manufacturer can do so.  This is fundamentally incompatible with the
+aim of protecting users' freedom to change the software.  The
+systematic pattern of such abuse occurs in the area of products for
+individuals to use, which is precisely where it is most unacceptable.
+Therefore, we have designed this version of the GPL to prohibit the
+practice for those products.  If such problems arise substantially in
+other domains, we stand ready to extend this provision to those
+domains in future versions of the GPL, as needed to protect the
+freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish
+to avoid the special danger that patents applied to a free program
+could make it effectively proprietary.  To prevent this, the GPL
+assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+@heading TERMS AND CONDITIONS
+
+@enumerate 0
+@item Definitions.
+
+``This License'' refers to version 3 of the GNU General Public License.
+
+``Copyright'' also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+``The Program'' refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as ``you''.  ``Licensees'' and
+``recipients'' may be individuals or organizations.
+
+To ``modify'' a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of
+an exact copy.  The resulting work is called a ``modified version'' of
+the earlier work or a work ``based on'' the earlier work.
+
+A ``covered work'' means either the unmodified Program or a work based
+on the Program.
+
+To ``propagate'' a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To ``convey'' a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user
+through a computer network, with no transfer of a copy, is not
+conveying.
+
+An interactive user interface displays ``Appropriate Legal Notices'' to
+the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+@item Source Code.
+
+The ``source code'' for a work means the preferred form of the work for
+making modifications to it.  ``Object code'' means any non-source form
+of a work.
+
+A ``Standard Interface'' means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The ``System Libraries'' of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+``Major Component'', in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The ``Corresponding Source'' for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can
+regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same
+work.
+
+@item Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey,
+without conditions so long as your license otherwise remains in force.
+You may convey covered works to others for the sole purpose of having
+them make modifications exclusively for you, or provide you with
+facilities for running those works, provided that you comply with the
+terms of this License in conveying all material for which you do not
+control copyright.  Those thus making or running the covered works for
+you must do so exclusively on your behalf, under your direction and
+control, on terms that prohibit them from making any copies of your
+copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+@item Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such
+circumvention is effected by exercising rights under this License with
+respect to the covered work, and you disclaim any intention to limit
+operation or modification of the work as a means of enforcing, against
+the work's users, your or third parties' legal rights to forbid
+circumvention of technological measures.
+
+@item Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+@item Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these
+conditions:
+
+@enumerate a
+@item
+The work must carry prominent notices stating that you modified it,
+and giving a relevant date.
+
+@item
+The work must carry prominent notices stating that it is released
+under this License and any conditions added under section 7.  This
+requirement modifies the requirement in section 4 to ``keep intact all
+notices''.
+
+@item
+You must license the entire work, as a whole, under this License to
+anyone who comes into possession of a copy.  This License will
+therefore apply, along with any applicable section 7 additional terms,
+to the whole of the work, and all its parts, regardless of how they
+are packaged.  This License gives no permission to license the work in
+any other way, but it does not invalidate such permission if you have
+separately received it.
+
+@item
+If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your work
+need not make them do so.
+@end enumerate
+
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+``aggregate'' if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+@item  Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of
+sections 4 and 5, provided that you also convey the machine-readable
+Corresponding Source under the terms of this License, in one of these
+ways:
+
+@enumerate a
+@item
+Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium customarily
+used for software interchange.
+
+@item
+Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by a written
+offer, valid for at least three years and valid for as long as you
+offer spare parts or customer support for that product model, to give
+anyone who possesses the object code either (1) a copy of the
+Corresponding Source for all the software in the product that is
+covered by this License, on a durable physical medium customarily used
+for software interchange, for a price no more than your reasonable
+cost of physically performing this conveying of source, or (2) access
+to copy the Corresponding Source from a network server at no charge.
+
+@item
+Convey individual copies of the object code with a copy of the written
+offer to provide the Corresponding Source.  This alternative is
+allowed only occasionally and noncommercially, and only if you
+received the object code with such an offer, in accord with subsection
+6b.
+
+@item
+Convey the object code by offering access from a designated place
+(gratis or for a charge), and offer equivalent access to the
+Corresponding Source in the same way through the same place at no
+further charge.  You need not require recipients to copy the
+Corresponding Source along with the object code.  If the place to copy
+the object code is a network server, the Corresponding Source may be
+on a different server (operated by you or a third party) that supports
+equivalent copying facilities, provided you maintain clear directions
+next to the object code saying where to find the Corresponding Source.
+Regardless of what server hosts the Corresponding Source, you remain
+obligated to ensure that it is available for as long as needed to
+satisfy these requirements.
+
+@item
+Convey the object code using peer-to-peer transmission, provided you
+inform other peers where the object code and Corresponding Source of
+the work are being offered to the general public at no charge under
+subsection 6d.
+
+@end enumerate
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A ``User Product'' is either (1) a ``consumer product'', which means any
+tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling.  In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of
+coverage.  For a particular product received by a particular user,
+``normally used'' refers to a typical or common use of that class of
+product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected
+to use, the product.  A product is a consumer product regardless of
+whether the product has substantial commercial, industrial or
+non-consumer uses, unless such uses represent the only significant
+mode of use of the product.
+
+``Installation Information'' for a User Product means any methods,
+procedures, authorization keys, or other information required to
+install and execute modified versions of a covered work in that User
+Product from a modified version of its Corresponding Source.  The
+information must suffice to ensure that the continued functioning of
+the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or
+updates for a work that has been modified or installed by the
+recipient, or for the User Product in which it has been modified or
+installed.  Access to a network may be denied when the modification
+itself materially and adversely affects the operation of the network
+or violates the rules and protocols for communication across the
+network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+@item Additional Terms.
+
+``Additional permissions'' are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+@enumerate a
+@item
+Disclaiming warranty or limiting liability differently from the terms
+of sections 15 and 16 of this License; or
+
+@item
+Requiring preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices
+displayed by works containing it; or
+
+@item
+Prohibiting misrepresentation of the origin of that material, or
+requiring that modified versions of such material be marked in
+reasonable ways as different from the original version; or
+
+@item
+Limiting the use for publicity purposes of names of licensors or
+authors of the material; or
+
+@item
+Declining to grant rights under trademark law for use of some trade
+names, trademarks, or service marks; or
+
+@item
+Requiring indemnification of licensors and authors of that material by
+anyone who conveys the material (or modified versions of it) with
+contractual assumptions of liability to the recipient, for any
+liability that these contractual assumptions directly impose on those
+licensors and authors.
+@end enumerate
+
+All other non-permissive additional terms are considered ``further
+restrictions'' within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions; the
+above requirements apply either way.
+
+@item Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+@item Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run
+a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+@item Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+An ``entity transaction'' is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+@item Patents.
+
+A ``contributor'' is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's ``contributor version''.
+
+A contributor's ``essential patent claims'' are all patent claims owned
+or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, ``control'' includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a ``patent license'' is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To ``grant'' such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  ``Knowingly relying'' means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is ``discriminatory'' if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on
+the non-exercise of one or more of the rights that are specifically
+granted under this License.  You may not convey a covered work if you
+are a party to an arrangement with a third party that is in the
+business of distributing software, under which you make payment to the
+third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties
+who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by
+you (or copies made from those copies), or (b) primarily for and in
+connection with specific products or compilations that contain the
+covered work, unless you entered into that arrangement, or that patent
+license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+@item No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey
+a covered work so as to satisfy simultaneously your obligations under
+this License and any other pertinent obligations, then as a
+consequence you may not convey it at all.  For example, if you agree
+to terms that obligate you to collect a royalty for further conveying
+from those to whom you convey the Program, the only way you could
+satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+@item Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+@item Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions
+of the GNU General Public License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies that a certain numbered version of the GNU General Public
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that numbered version or
+of any later version published by the Free Software Foundation.  If
+the Program does not specify a version number of the GNU General
+Public License, you may choose any version ever published by the Free
+Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions
+of the GNU General Public License can be used, that proxy's public
+statement of acceptance of a version permanently authorizes you to
+choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+@item Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW@.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE@.  THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU@.  SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+@item Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+@item Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+@end enumerate
+
+@heading END OF TERMS AND CONDITIONS
+
+@heading How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) @var{year} @var{name of author}
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE@.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see @url{https://www.gnu.org/licenses/}.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+@smallexample
+@var{program} Copyright (C) @var{year} @var{name of author}
+This program comes with ABSOLUTELY NO WARRANTY; for details type @samp{show w}.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type @samp{show c} for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License.  Of course, your
+program's commands might be different; for a GUI interface, you would
+use an ``about box''.
+
+You should also get your employer (if you work as a programmer) or school,
+if any, to sign a ``copyright disclaimer'' for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+@url{https://www.gnu.org/licenses/}.
+
+The GNU General Public License does not permit incorporating your
+program into proprietary programs.  If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library.  If this is what you want to do, use
+the GNU Lesser General Public License instead of this License.  But
+first, please read @url{https://www.gnu.org/licenses/why-not-lgpl.html}.
diff --git a/make-changelog b/make-changelog
new file mode 100755
index 0000000000..b5aa113a0c
--- /dev/null
+++ b/make-changelog
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+./gitlog-to-changelog --ignore-matching='^; ' --ignore-line='^; ' \
+                      --format='%B' >ChangeLog
+
+# Find the years covered by the generated ChangeLog, so that
+# a proper copyright notice can be output.
+years=$(sed -n 's/^\([0-9][0-9]*\).*/\1/p' ChangeLog | sort -nu)
+start_year=$(echo "$years" | head)
+end_year=$(echo "$years" | tail)
+
+if test "$start_year" = "$end_year"; then
+  year_range=$start_year
+else
+  year_range=$start_year-$end_year
+fi
+
+copyright_notice="
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+  Copyright (C) $year_range Akib Azmain Turja.
+
+  This file is not part of GNU Emacs.
+
+  GNU Emacs is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  GNU Emacs is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>."
+
+echo "$copyright_notice" >>ChangeLog
diff --git a/texinfo.tex b/texinfo.tex
new file mode 100644
index 0000000000..deca599187
--- /dev/null
+++ b/texinfo.tex
@@ -0,0 +1,11614 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2020-02-11.09}
+%
+% Copyright 1985, 1986, 1988, 1990-2019 Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software: you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation, either version 3 of the
+% License, or (at your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program.  If not, see <https://www.gnu.org/licenses/>.
+%
+% As a special exception, when this file is read by TeX when processing
+% a Texinfo source document, you may use the result without
+% restriction. This Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   https://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+%   https://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+%   https://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org.  Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem.  Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For a simple
+% manual foo.texi, however, you can get away with this:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o  # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent.  You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is https://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+% LaTeX's \typeout.  This ensures that the messages it is used for
+% are identical in format to the corresponding ones from latex/pdflatex.
+\def\typeout{\immediate\write17}%
+
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexsp=\sp
+\let\ptexstar=\*
+\let\ptexsup=\sup
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Pre-3.0.
+\else
+  \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined  \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined   \gdef\putwordChapter{Chapter}\fi
+\ifx\putworderror\undefined     \gdef\putworderror{error}\fi
+\ifx\putwordfile\undefined      \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined        \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined       \gdef\putwordIndexIsEmpty{(Index is 
empty)}\fi
+\ifx\putwordIndexNonexistent\undefined   \gdef\putwordIndexNonexistent{(Index 
is nonexistent)}\fi
+\ifx\putwordInfo\undefined      \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined 
\gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined  \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined   \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined        \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined        \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined      \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined   \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined   \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined       \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined       \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined  \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined       \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined    \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined   \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined    \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined    \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined   \gdef\putwordDeffunc{Function}\fi
+
+% Give the space character the catcode for a space.
+\def\spaceisspace{\catcode`\ =10\relax}
+
+% Likewise for ^^M, the end of line character.
+\def\endlineisspace{\catcode13=10\relax}
+
+\chardef\dashChar  = `\-
+\chardef\slashChar = `\/
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+  Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+  ap-pen-dix bit-map bit-maps
+  data-base data-bases eshell fall-ing half-way long-est man-u-script
+  man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+  par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+  spell-ing spell-ings
+  stand-alone strong-est time-stamp time-stamps which-ever white-space
+  wide-spread wrap-around
+}
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.  We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+  \tracingstats2
+  \tracingpages1
+  \tracinglostchars2  % 2 gives us more in etex
+  \tracingparagraphs1
+  \tracingoutput1
+  \tracingmacros2
+  \tracingrestores1
+  \showboxbreadth\maxdimen \showboxdepth\maxdimen
+  \ifx\eTeXversion\thisisundefined\else % etex gives us more logging
+    \tracingscantokens1
+    \tracingifs1
+    \tracinggroups1
+    \tracingnesting2
+    \tracingassigns1
+  \fi
+  \tracingcommands3  % 3 gives us more in etex
+  \errorcontextlines16
+}%
+
+% @errormsg{MSG}.  Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+%
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% add check for \lastpenalty to plain's definitions.  If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+  \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+  \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+  \removelastskip\penalty-200\bigskip\fi\fi}
+
+% Output routine
+%
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt }
+
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Output a mark which sets \thischapter, \thissection and \thiscolor.
+% We dump everything together because we only have one kind of mark.
+% This works because we only use \botmark / \topmark, not \firstmark.
+%
+% A mark contains a subexpression of the \ifcase ... \fi construct.
+% \get*marks macros below extract the needed part using \ifcase.
+%
+% Another complication is to let the user choose whether \thischapter
+% (\thissection) refers to the chapter (section) in effect at the top
+% of a page, or that at the bottom of a page.
+
+% \domark is called twice inside \chapmacro, to add one
+% mark before the section break, and one after.
+%   In the second call \prevchapterdefs is the same as \currentchapterdefs,
+% and \prevsectiondefs is the same as \currentsectiondefs.
+%   Then if the page is not broken at the mark, some of the previous
+% section appears on the page, and we can get the name of this section
+% from \firstmark for @everyheadingmarks top.
+%   @everyheadingmarks bottom uses \botmark.
+%
+% See page 260 of The TeXbook.
+\def\domark{%
+  \toks0=\expandafter{\currentchapterdefs}%
+  \toks2=\expandafter{\currentsectiondefs}%
+  \toks4=\expandafter{\prevchapterdefs}%
+  \toks6=\expandafter{\prevsectiondefs}%
+  \toks8=\expandafter{\currentcolordefs}%
+  \mark{%
+                   \the\toks0 \the\toks2  % 0: marks for @everyheadingmarks top
+      \noexpand\or \the\toks4 \the\toks6  % 1: for @everyheadingmarks bottom
+    \noexpand\else \the\toks8             % 2: color marks
+  }%
+}
+
+% \gettopheadingmarks, \getbottomheadingmarks,
+% \getcolormarks - extract needed part of mark.
+%
+% \topmark doesn't work for the very first chapter (after the title
+% page or the contents), so we use \firstmark there -- this gets us
+% the mark with the chapter defs, unless the user sneaks in, e.g.,
+% @setcolor (or @url, or @link, etc.) between @contents and the very
+% first @chapter.
+\def\gettopheadingmarks{%
+  \ifcase0\the\savedtopmark\fi
+  \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\the\savedtopmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\currentchapterdefs{}
+\def\currentsectiondefs{}
+\def\currentsection{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\currentcolordefs{}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\txipagewidth \newdimen\txipageheight
+
+% Main output routine.
+%
+\chardef\PAGE = 255
+\newtoks\defaultoutput
+\defaultoutput = {\savetopmark\onepageout{\pagecontents\PAGE}}
+\output=\expandafter{\the\defaultoutput}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% When outputting the double column layout for indices, an output routine
+% is run several times, which hides the original value of \topmark.  This
+% can lead to a page heading being output and duplicating the chapter heading
+% of the index.  Hence, save the contents of \topmark at the beginning of
+% the output routine.  The saved contents are valid until we actually
+% \shipout a page.
+%
+% (We used to run a short output routine to actually set \topmark and
+% \firstmark to the right values, but if this was called with an empty page
+% containing whatsits for writing index entries, the whatsits would be thrown
+% away and the index auxiliary file would remain empty.)
+%
+\newtoks\savedtopmark
+\newif\iftopmarksaved
+\topmarksavedtrue
+\def\savetopmark{%
+  \iftopmarksaved\else
+    \global\savedtopmark=\expandafter{\topmark}%
+    \global\topmarksavedtrue
+  \fi
+}
+
+% \onepageout takes a vbox as an argument.
+% \shipout a vbox for a single page, adding an optional header, footer
+% and footnote.  This also causes index entries for this page to be written
+% to the auxiliary files.
+%
+\def\onepageout#1{%
+  \hoffset=\normaloffset
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  % Retrieve the information for the headings from the marks in the page,
+  % and call Plain TeX's \makeheadline and \makefootline, which use the
+  % values in \headline and \footline.
+  %
+  % This is used to check if we are on the first page of a chapter.
+  \ifcase1\the\savedtopmark\fi
+  \let\prevchaptername\thischaptername
+  \ifcase0\firstmark\fi
+  \let\curchaptername\thischaptername
+  %
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  %
+  \ifx\curchaptername\prevchaptername
+    \let\thischapterheading\thischapter
+  \else
+    % \thischapterheading is the same as \thischapter except it is blank
+    % for the first page of a chapter.  This is to prevent the chapter name
+    % being shown twice.
+    \def\thischapterheading{}%
+  \fi
+  %
+  % Common context changes for both heading and footing.
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \def\commonheadfootline{\let\hsize=\txipagewidth \texinfochars}
+  %
+  \global\setbox\headlinebox = \vbox{\commonheadfootline \makeheadline}%
+  %
+  \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+  \global\setbox\footlinebox = \vbox{\commonheadfootline \makefootline}%
+  %
+  {%
+    % Set context for writing to auxiliary files like index files.
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \atdummies         % don't expand commands in the output.
+    \turnoffactive
+    \shipout\vbox{%
+      % Do this early so pdf references go to the beginning of the page.
+      \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingyyy.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 24pt
+        \unvbox\footlinebox
+      \fi
+      %
+    }%
+  }%
+  \global\topmarksavedfalse
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+% Main part of page, including any footnotes
+\def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1\relax \unvbox#1\relax
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+
+% Argument parsing
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+% For example, \def\foo{\parsearg\fooxxx}.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+  \def\argtorun{#2}%
+  \begingroup
+    \obeylines
+    \spaceisspace
+    #1%
+    \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    \argremovecomment #1\comment\ArgTerm%
+  }%
+}
+
+% First remove any @comment, then any @c comment.  Pass the result on to
+% \argcheckspaces.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurrence of `\^^M' or `<space>\^^M' is replaced by a single space.
+%
+% \argremovec might leave us with trailing space, e.g.,
+%    @end itemize  @c foo
+% This space token undergoes the same procedure and is eventually removed
+% by \finishparsearg.
+%
+\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M}
+\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M}
+\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{%
+  \def\temp{#3}%
+  \ifx\temp\empty
+    % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp:
+    \let\temp\finishparsearg
+  \else
+    \let\temp\argcheckspaces
+  \fi
+  % Put the space token in:
+  \temp#1 #3\ArgTerm
+}
+
+% If a _delimited_ argument is enclosed in braces, they get stripped; so
+% to get _exactly_ the rest of the line, we had to prevent such situation.
+% We prepended an \empty token at the very beginning and we expand it now,
+% just before passing the control to \argtorun.
+% (Similarly, we have to think about #3 of \argcheckspacesY above: it is
+% either the null string, or it ends with \^^M---thus there is no danger
+% that a pair of braces would be stripped.
+%
+% But first, we have to remove the trailing space token.
+%
+\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}}
+
+
+% \parseargdef - define a command taking an argument on the line
+%
+% \parseargdef\foo{...}
+%      is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+\def\parseargdef#1{%
+  \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+  \def#2{\parsearg#1}%
+  \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+  \obeyspaces
+  \gdef\obeyedspace{ }
+
+  % Make each space character in the input produce a normal interword
+  % space in the output.  Don't allow a line break at this space, as this
+  % is used only in environments like @example, where each line of input
+  % should produce a line of output anyway.
+  %
+  \gdef\sepspaces{\obeyspaces\let =\tie}
+
+  % If an index command is used in an @example environment, any spaces
+  % therein should become regular spaces in the raw index file, not the
+  % expansion of \tie (\leavevmode \penalty \@M \ ).
+  \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex.  It's used like this:
+%
+%   \envdef\foo{...}
+%   \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo.  \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches.  The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as environments; they don't open a group.  (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At run-time, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+  \def\temp{#1}%
+  \ifx\thisenv\temp
+  \else
+    \badenverr
+  \fi
+}
+
+% Environment mismatch, #1 expected:
+\def\badenverr{%
+  \errhelp = \EMsimple
+  \errmessage{This command can appear only \inenvironment\temp,
+    not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+  \ifx#1\empty
+    outside of any environment%
+  \else
+    in environment \expandafter\string#1%
+  \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+  \if 1\csname iscond.#1\endcsname
+  \else
+    % The general wording of \badenverr may not be ideal.
+    \expandafter\checkenv\csname#1\endcsname
+    \csname E#1\endcsname
+    \endgroup
+  \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\unskip\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off  says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+  \def\temp{#1}%
+  \ifx\temp\onword \plainfrenchspacing
+  \else\ifx\temp\offword \plainnonfrenchspacing
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @frenchspacing option `\temp', must be on|off}%
+  \fi\fi
+}
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large.  This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material.  In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom.  The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+  \ifnum\catcode`\^^M=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  \startsavinginserts
+  %
+  \setbox\groupbox = \vtop\bgroup
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it.  Thus, space below is not quite equal to space
+% above.  But it's pretty close.
+\def\Egroup{%
+    % To get correct interline space between the last line of the group
+    % and the first line afterwards, we have to propagate \prevdepth.
+    \endgraf % Not \par, as it may have been set to \lisppar.
+    \global\dimen1 = \prevdepth
+  \egroup           % End the \vtop.
+  \addgroupbox
+  \prevdepth = \dimen1
+  \checkinserts
+}
+
+\def\addgroupbox{
+  % \dimen0 is the vertical size of the group's box.
+  \dimen0 = \ht\groupbox  \advance\dimen0 by \dp\groupbox
+  % \dimen2 is how much space is left on the page (more or less).
+  \dimen2 = \txipageheight   \advance\dimen2 by -\pagetotal
+  % if the group doesn't fit on the current page, and it's a big big
+  % group, force a page break.
+  \ifdim \dimen0 > \dimen2
+    \ifdim \pagetotal < \vfilllimit\txipageheight
+      \page
+    \fi
+  \fi
+  \box\groupbox
+}
+
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\parseargdef\need{%
+  % Ensure vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % If the @need value is less than one line space, it's useless.
+  \dimen0 = #1\mil
+  \dimen2 = \ht\strutbox
+  \advance\dimen2 by \dp\strutbox
+  \ifdim\dimen0 > \dimen2
+    %
+    % Do a \strut just to make the height of this box be normal, so the
+    % normal leading is inserted relative to the preceding line.
+    % And a page break here is fine.
+    \vtop to #1\mil{\strut\vfil}%
+    %
+    % TeX does not even consider page breaks if a penalty added to the
+    % main vertical list is 10000 or more.  But in order to see if the
+    % empty box we just added fits on the page, we must make it consider
+    % page breaks.  On the other hand, we don't want to actually break the
+    % page after the empty box.  So we use a penalty of 9999.
+    %
+    % There is an extremely small chance that TeX will actually break the
+    % page at this \penalty, if there are no other feasible breakpoints in
+    % sight.  (If the user is using lots of big @group commands, which
+    % almost-but-not-quite fill up a page, TeX will have a hard time doing
+    % good page breaking, for example.)  However, I could not construct an
+    % example where a page broke at this \penalty; if it happens in a real
+    % document, then we can reconsider our strategy.
+    \penalty9999
+    %
+    % Back up by the size of the box, whether we did a page break or not.
+    \kern -#1\mil
+    %
+    % Do not allow a page break right after this kern.
+    \nobreak
+  \fi
+}
+
+% @br   forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+  \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph.  For more general purposes, use the \margin insertion
+% class.  WHICH is `l' or `r'.  Not documented, written for gawk manual.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+  \nobreak
+  \kern-\strutdepth
+  \vtop to \strutdepth{%
+    \baselineskip=\strutdepth
+    \vss
+    % if you have multiple lines of stuff to put here, you'll need to
+    % make the vbox yourself of the appropriate size.
+    \ifx#1l%
+      \llap{\ignorespaces #2\hskip\inmarginspacing}%
+    \else
+      \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+    \fi
+    \null
+  }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+  \setbox0 = \hbox{\ignorespaces #2}%
+  \ifdim\wd0 > 0pt
+    \def\lefttext{#1}%  have both texts
+    \def\righttext{#2}%
+  \else
+    \def\lefttext{#1}%  have only one text
+    \def\righttext{#1}%
+  \fi
+  %
+  \ifodd\pageno
+    \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+  \else
+    \def\temp{\inleftmargin\lefttext}%
+  \fi
+  \temp
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+  \pushthisfilestack
+  \def\thisfile{#1}%
+  {%
+    \makevalueexpandable  % we want to expand any @value in FILE.
+    \turnoffactive        % and allow special characters in the expansion
+    \indexnofonts         % Allow `@@' and other weird things in file names.
+    \wlog{texinfo.tex: doing @include of #1^^J}%
+    \edef\temp{\noexpand\input #1 }%
+    %
+    % This trickery is to read FILE outside of a group, in case it makes
+    % definitions, etc.
+    \expandafter
+  }\temp
+  \popthisfilestack
+}
+\def\filenamecatcodes{%
+  \catcode`\\=\other
+  \catcode`~=\other
+  \catcode`^=\other
+  \catcode`_=\other
+  \catcode`|=\other
+  \catcode`<=\other
+  \catcode`>=\other
+  \catcode`+=\other
+  \catcode`-=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+  \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+  \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+  \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+  the stack of filenames is empty.}}
+%
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+  \ifhmode
+    \let\centersub\centerH
+  \else
+    \let\centersub\centerV
+  \fi
+  \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+  \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+  \hfil\break
+  \advance\hsize by -\leftskip
+  \advance\hsize by -\rightskip
+  \line{#1}%
+  \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+  % The idea here is the same as in \startdefun, \cartouche, etc.: if
+  % @center is the first thing after a section heading, we need to wipe
+  % out the negative parskip inserted by \sectionheading, but still
+  % prevent a page break here.
+  \centerpenalty = \lastpenalty
+  \ifnum\centerpenalty>10000 \vskip\parskip \fi
+  \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+  \line{\kern\leftskip #1\kern\rightskip}%
+}
+
+% @sp n   outputs n lines of vertical space
+%
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+
+\def\c{\begingroup \catcode`\^^M=\active%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\cxxx}
+{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}}
+%
+\let\comment\c
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \defaultparindent = 0pt
+    \else
+      \defaultparindent = #1em
+    \fi
+  \fi
+  \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \lispnarrowing = 0pt
+    \else
+      \lispnarrowing = #1em
+    \fi
+  \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading.  If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\noneword
+    \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+  \else\ifx\temp\insertword
+    \let\suppressfirstparagraphindent = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @firstparagraphindent option `\temp'}%
+  \fi\fi
+}
+
+% Here is how we actually suppress indentation.  Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+  \gdef\indent  {\restorefirstparagraphindent \indent}%
+  \gdef\noindent{\restorefirstparagraphindent \noindent}%
+  \global\everypar = {\kern -\parindent \restorefirstparagraphindent}%
+}
+%
+\gdef\restorefirstparagraphindent{%
+  \global\let\indent = \ptexindent
+  \global\let\noindent = \ptexnoindent
+  \global\everypar = {}%
+}
+
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% @setfilename INFO-FILENAME - ignored
+\let\setfilename=\comment
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newbox\boxB
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+%
+% For LuaTeX
+%
+
+\newif\iftxiuseunicodedestname
+\txiuseunicodedestnamefalse % For pdfTeX etc.
+
+\ifx\luatexversion\thisisundefined
+\else
+  % Use Unicode destination names
+  \txiuseunicodedestnametrue
+  % Escape PDF strings with converting UTF-16 from UTF-8
+  \begingroup
+    \catcode`\%=12
+    \directlua{
+      function UTF16oct(str)
+        tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377')
+        for c in string.utfvalues(str) do
+          if c < 0x10000 then
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c / 256), math.floor(c % 256)))
+          else
+            c = c - 0x10000
+            local c_hi = c / 1024 + 0xd800
+            local c_lo = c % 1024 + 0xdc00
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c_hi / 256), math.floor(c_hi % 256),
+                            math.floor(c_lo / 256), math.floor(c_lo % 256)))
+          end
+        end
+      end
+    }
+  \endgroup
+  \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}}
+  % Escape PDF strings without converting
+  \begingroup
+    \directlua{
+      function PDFescstr(str)
+        for c in string.bytes(str) do
+          if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then
+            tex.sprint(-2,
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o',
+                            c))
+          else
+            tex.sprint(-2, string.char(c))
+          end
+        end
+      end
+    }
+    % The -2 in the arguments here gives all the input to TeX catcode 12
+    % (other) or 10 (space), preventing undefined control sequence errors. See
+    % https://lists.gnu.org/archive/html/bug-texinfo/2019-08/msg00031.html
+    %
+  \endgroup
+  \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}}
+  \ifnum\luatexversion>84
+    % For LuaTeX >= 0.85
+    \def\pdfdest{\pdfextension dest}
+    \let\pdfoutput\outputmode
+    \def\pdfliteral{\pdfextension literal}
+    \def\pdfcatalog{\pdfextension catalog}
+    \def\pdftexversion{\numexpr\pdffeedback version\relax}
+    \let\pdfximage\saveimageresource
+    \let\pdfrefximage\useimageresource
+    \let\pdflastximage\lastsavedimageresourceindex
+    \def\pdfendlink{\pdfextension endlink\relax}
+    \def\pdfoutline{\pdfextension outline}
+    \def\pdfstartlink{\pdfextension startlink}
+    \def\pdffontattr{\pdfextension fontattr}
+    \def\pdfobj{\pdfextension obj}
+    \def\pdflastobj{\numexpr\pdffeedback lastobj\relax}
+    \let\pdfpagewidth\pagewidth
+    \let\pdfpageheight\pageheight
+    \edef\pdfhorigin{\pdfvariable horigin}
+    \edef\pdfvorigin{\pdfvariable vorigin}
+  \fi
+\fi
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set).  So we test for \relax and 0 as well as being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+\newif\ifpdforxetex
+\pdforxetexfalse
+\ifpdf
+  \pdforxetextrue
+\fi
+\ifx\XeTeXrevision\thisisundefined\else
+  \pdforxetextrue
+\fi
+
+
+% PDF uses PostScript string constants for the names of xref targets,
+% for display in the outlines, and in other places.  Thus, we have to
+% double any backslashes.  Otherwise, a name like "\node" will be
+% interpreted as a newline (\n), followed by o, d, e.  Not good.
+%
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% related messages.  The final outcome is that it is up to the TeX user
+% to double the backslashes and otherwise make the string valid, so
+% that's what we do.  pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+  \ifx\pdfescapestring\thisisundefined
+    % No primitive available; should we give a warning or log?
+    % Many times it won't matter.
+    \xdef#1{#1}%
+  \else
+    % The expandable \pdfescapestring primitive escapes parentheses,
+    % backslashes, and other special chars.
+    \xdef#1{\pdfescapestring{#1}}%
+  \fi
+}
+\def\txiescapepdfutfsixteen#1{%
+  \ifx\pdfescapestrutfsixteen\thisisundefined
+    % No UTF-16 converting macro available.
+    \txiescapepdf{#1}%
+  \else
+    \xdef#1{\pdfescapestrutfsixteen{#1}}%
+  \fi
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found.  (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+  %
+  % Color manipulation macros using ideas from pdfcolor.tex,
+  % except using rgb instead of cmyk; the latter is said to render as a
+  % very dark gray on-screen and a very dark halftone in print, instead
+  % of actual black. The dark red here is dark enough to print on paper as
+  % nearly black, but still distinguishable for online viewing.  We use
+  % black by default, though.
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  % rg sets the color for filling (usual text, etc.);
+  % RG sets the color for stroking (thin rules, e.g., normal _'s).
+  \def\pdfsetcolor#1{\pdfliteral{#1 rg  #1 RG}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  %
+  \pdfcatalog{/PageMode /UseOutlines}
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\dopdfimage#1#2#3{%
+    \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\pdfimgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errhelp = \nopdfimagehelp
+                  \errmessage{Could not find image file #1 for pdf}%
+                \else \gdef\pdfimgext{JPG}%
+                \fi
+              \else \gdef\pdfimgext{jpeg}%
+              \fi
+            \else \gdef\pdfimgext{jpg}%
+            \fi
+          \else \gdef\pdfimgext{png}%
+          \fi
+        \else \gdef\pdfimgext{PDF}%
+        \fi
+      \else \gdef\pdfimgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    % without \immediate, ancient pdftex seg faults when the same image is
+    % included twice.  (Version 3.14159-pre-1.0-unofficial-20010704.)
+    \ifnum\pdftexversion < 14
+      \immediate\pdfimage
+    \else
+      \immediate\pdfximage
+    \fi
+      \ifdim \wd0 >0pt width \pdfimagewidth \fi
+      \ifdim \wd2 >0pt height \pdfimageheight \fi
+      \ifnum\pdftexversion<13
+         #1.\pdfimgext
+       \else
+         {#1.\pdfimgext}%
+       \fi
+    \ifnum\pdftexversion < 14 \else
+      \pdfrefximage \pdflastximage
+    \fi}
+  %
+  \def\setpdfdestname#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      \ifx \declaredencoding \latone
+        % Pass through Latin-1 characters.
+        % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode.
+      \else
+        \ifx \declaredencoding \utfeight
+          % Pass through Unicode characters.
+        \else
+          % Use ASCII approximations in destination names.
+          \passthroughcharsfalse
+        \fi
+      \fi
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \ifx \declaredencoding \latone
+      % The PDF format can use an extended form of Latin-1 in bookmark
+      % strings.  See Appendix D of the PDF Reference, Sixth Edition, for
+      % the "PDFDocEncoding".
+      \passthroughcharstrue
+      % Pass through Latin-1 characters.
+      %   LuaTeX: Convert to Unicode
+      %   pdfTeX: Use Latin-1 as PDFDocEncoding
+      \def\pdfoutlinetext{#1}%
+    \else
+      \ifx \declaredencoding \utfeight
+        \ifx\luatexversion\thisisundefined
+          % For pdfTeX  with UTF-8.
+          % TODO: the PDF format can use UTF-16 in bookmark strings,
+          % but the code for this isn't done yet.
+          % Use ASCII approximations.
+          \passthroughcharsfalse
+          \def\pdfoutlinetext{#1}%
+        \else
+          % For LuaTeX with UTF-8.
+          % Pass through Unicode characters for title texts.
+          \passthroughcharstrue
+          \def\pdfoutlinetext{#1}%
+        \fi
+      \else
+        % For non-Latin-1 or non-UTF-8 encodings.
+        % Use ASCII approximations.
+        \passthroughcharsfalse
+        \def\pdfoutlinetext{#1}%
+      \fi
+    \fi
+    % LuaTeX: Convert to UTF-16
+    % pdfTeX: Use Latin-1 as PDFDocEncoding
+    \txiescapepdfutfsixteen\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % used to mark target names; must be expandable.
+  \def\pdfmkpgn#1{#1}
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  % Adding outlines to PDF; macros for calculating structure of outlines
+  % come from Petr Olsak
+  \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+    \else \csname#1\endcsname \fi}
+  \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+    \advance\tempnum by 1
+    \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+  %
+  % #1 is the section text, which is what will be displayed in the
+  % outline by the pdf viewer.  #2 is the pdf expression for the number
+  % of subentries (or empty, for subsubsections).  #3 is the node text,
+  % which might be empty if this toc entry had no corresponding node.
+  % #4 is the page number
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    % Generate a link to the node text if that exists; else, use the
+    % page number.  We could generate a destination for the section
+    % text in the case where a section has no node, but it doesn't
+    % seem worth the trouble, since most documents are normally structured.
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      % Read toc silently, to get counts of subentries for \pdfoutline.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+       \def\thischapnum{##2}%
+       \def\thissecnum{0}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsecentry##1##2##3##4{%
+       \advancenumber{chap\thischapnum}%
+       \def\thissecnum{##2}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsubsecentry##1##2##3##4{%
+       \advancenumber{sec\thissecnum}%
+       \def\thissubsecnum{##2}%
+      }%
+      \def\numsubsubsecentry##1##2##3##4{%
+       \advancenumber{subsec\thissubsecnum}%
+      }%
+      \def\thischapnum{0}%
+      \def\thissecnum{0}%
+      \def\thissubsecnum{0}%
+      %
+      % use \def rather than \let here because we redefine \chapentry et
+      % al. a second time, below.
+      \def\appentry{\numchapentry}%
+      \def\appsecentry{\numsecentry}%
+      \def\appsubsecentry{\numsubsecentry}%
+      \def\appsubsubsecentry{\numsubsubsecentry}%
+      \def\unnchapentry{\numchapentry}%
+      \def\unnsecentry{\numsecentry}%
+      \def\unnsubsecentry{\numsubsecentry}%
+      \def\unnsubsubsecentry{\numsubsubsecentry}%
+      \readdatafile{toc}%
+      %
+      % Read toc second time, this time actually producing the outlines.
+      % The `-' means take the \expnumber as the absolute number of
+      % subentries, which we calculated on our first read of the .toc above.
+      %
+      % We use the node names as the destinations.
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{% count is always zero
+        \dopdfoutline{##1}{}{##3}{##4}}%
+      %
+      % PDF outlines are displayed using system fonts, instead of
+      % document fonts.  Therefore we cannot use special characters,
+      % since the encoding is unknown.  For example, the eogonek from
+      % Latin 2 (0xea) gets translated to a | character.  Info from
+      % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+      %
+      % TODO this right, we have to translate 8-bit characters to
+      % their "best" equivalent, based on the @documentencoding.  Too
+      % much work for too little return.  Just use the ASCII equivalents
+      % we use for the index sort strings.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+  %
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  \ifnum\pdftexversion < 14
+    \let \startlink \pdfannotlink
+  \else
+    \let \startlink \pdfstartlink
+  \fi
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \startlink attr{/Border [0 0 0]}%
+        user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+    \endgroup}
+  % \pdfgettoks - Surround page numbers in #1 with @pdflink.  #1 may
+  % be a simple number, or a list of numbers in the case of an index
+  % entry.
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+  % non-pdf mode
+  \let\pdfmkdest = \gobble
+  \let\pdfurl = \gobble
+  \let\endlink = \relax
+  \let\setcolor = \gobble
+  \let\pdfsetcolor = \gobble
+  \let\pdfmakeoutlines = \relax
+\fi  % \ifx\pdfoutput
+
+%
+% For XeTeX
+%
+\ifx\XeTeXrevision\thisisundefined
+\else
+  %
+  % XeTeX version check
+  %
+  \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1
+    % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307.
+    % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941).
+    % For avoiding PDF destination name replacement, we use this special
+    % instead of xdvipdfmx's command line option `-C 0x0010'.
+    \special{dvipdfmx:config C 0x0010}
+    % XeTeX 0.99995+ comes with xdvipdfmx 20160307+.
+    % It can handle Unicode destination names for PDF.
+    \txiuseunicodedestnametrue
+  \else
+    % XeTeX < 0.99996 (TeX Live < 2016) cannot use the
+    % `dvipdfmx:config' special.
+    % So for avoiding PDF destination name replacement,
+    % xdvipdfmx's command line option `-C 0x0010' is necessary.
+    %
+    % XeTeX < 0.99995 can not handle Unicode destination names for PDF
+    % because xdvipdfmx 20150315 has a UTF-16 conversion issue.
+    % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+    \txiuseunicodedestnamefalse
+  \fi
+  %
+  % Color support
+  %
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  \def\pdfsetcolor#1{\special{pdf:scolor [#1]}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  % PDF outline support
+  %
+  % Emulate pdfTeX primitive
+  \def\pdfdest name#1 xyz{%
+    \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}%
+  }
+  %
+  \def\setpdfdestname#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      % Pass through Unicode characters.
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \turnoffactive
+    % Always use Unicode characters in title texts.
+    \def\pdfoutlinetext{#1}%
+    % For XeTeX, xdvipdfmx converts to UTF-16.
+    % So we do not convert.
+    \txiescapepdf\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A
+      << /S /GoTo /D (\pdfdestname) >> >> }%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      %
+      % For XeTeX, counts of subentries are not necessary.
+      % Therefore, we read toc only once.
+      %
+      % We use node names as destinations.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{1}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{2}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{3}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{4}{##3}{##4}}%
+      %
+      \let\appentry\numchapentry%
+      \let\appsecentry\numsecentry%
+      \let\appsubsecentry\numsubsecentry%
+      \let\appsubsubsecentry\numsubsubsecentry%
+      \let\unnchapentry\numchapentry%
+      \let\unnsecentry\numsecentry%
+      \let\unnsubsecentry\numsubsecentry%
+      \let\unnsubsubsecentry\numsubsubsecentry%
+      %
+      % For XeTeX, xdvipdfmx converts strings to UTF-16.
+      % Therefore, the encoding and the language may not be considered.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+
+  \special{pdf:docview << /PageMode /UseOutlines >> }
+  % ``\special{pdf:tounicode ...}'' is not necessary
+  % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it.
+  % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315,
+  % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings.
+  % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+%
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \special{pdf:bann << /Border [0 0 0]
+        /Subtype /Link /A << /S /URI /URI (#1) >> >>}%
+    \endgroup}
+  \def\endlink{\setcolor{\maincolor}\special{pdf:eann}}
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \special{pdf:bann << /Border [0 0 0]
+      /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}%
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+%
+  %
+  % @image support
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\doxeteximage#1#2#3{%
+    \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\xeteximgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errmessage{Could not find image file #1 for XeTeX}%
+                \else \gdef\xeteximgext{JPG}%
+                \fi
+              \else \gdef\xeteximgext{jpeg}%
+              \fi
+            \else \gdef\xeteximgext{jpg}%
+            \fi
+          \else \gdef\xeteximgext{png}%
+          \fi
+        \else \gdef\xeteximgext{PDF}%
+        \fi
+      \else \gdef\xeteximgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    \def\xetexpdfext{pdf}%
+    \ifx\xeteximgext\xetexpdfext
+      \XeTeXpdffile "#1".\xeteximgext ""
+    \else
+      \def\xetexpdfext{PDF}%
+      \ifx\xeteximgext\xetexpdfext
+        \XeTeXpdffile "#1".\xeteximgext ""
+      \else
+        \XeTeXpicfile "#1".\xeteximgext ""
+      \fi
+    \fi
+    \ifdim \wd0 >0pt width \xeteximagewidth \fi
+    \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+  }
+\fi
+
+
+%
+\message{fonts,}
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\newdimen\textleading
+\def\setleading#1{%
+  \dimen0 = #1\relax
+  \normalbaselineskip = \baselinefactor\dimen0
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% PDF CMaps.  See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\thisisundefined \else
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1IT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1TT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\def\setfont#1#2#3#4#5{%
+  \font#1=\fontprefix#2#3 scaled #4
+  \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+%
+% (end of cmaps)
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\thisisundefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               % where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt.  (The default in Texinfo.)
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\defsl\slshape{10}{\magstep1}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\ttslfont=\defttsl \let\slfont=\defsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}{OT1}
+\setfont\chapit\itbshape{10}{\magstep3}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep3}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT}
+\setfont\chapsf\sfbshape{17}{1000}{OT1}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}{OT1}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+\def\chapecsize{1728}
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}{OT1}
+\setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1}
+\setfont\secit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep2}{OT1}
+\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\secsf\sfbshape{12}{\magstep1}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}{OT1}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+\def\sececsize{1440}
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1}
+\setfont\ssecit\itbshape{10}{1315}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1315}{OT1}
+\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}{OT1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+\def\ssececsize{1200}
+
+% Reduced fonts for @acronym in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}{OT1}
+\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{1000}{OT1}
+\setfont\reducedit\itshape{10}{1000}{OT1IT}
+\setfont\reducedsl\slshape{10}{1000}{OT1}
+\setfont\reducedsf\sfshape{10}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{1000}{OT1}
+\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+\def\reducedecsize{1000}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit.  This is for the GNU
+% Press printing of the Emacs 22 manual.  Maybe other manuals in the
+% future.  Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\defsl\slshape{10}{\magstephalf}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\slfont=\defsl \let\ttslfont=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter fonts (14.4pt).
+\def\chapnominalsize{14pt}
+\setfont\chaprm\rmbshape{12}{\magstep1}{OT1}
+\setfont\chapit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep2}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\chapsf\sfbshape{12}{\magstep1}{OT1}
+\let\chapbf\chaprm
+\setfont\chapsc\scbshape{10}{\magstep2}{OT1}
+\font\chapi=cmmi12 scaled \magstep1
+\font\chapsy=cmsy10 scaled \magstep2
+\def\chapecsize{1440}
+
+% Section fonts (12pt).
+\def\secnominalsize{12pt}
+\setfont\secrm\rmbshape{12}{1000}{OT1}
+\setfont\secit\itbshape{10}{\magstep1}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep1}{OT1}
+\setfont\sectt\ttbshape{12}{1000}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT}
+\setfont\secsf\sfbshape{12}{1000}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep1}{OT1}
+\font\seci=cmmi12
+\font\secsy=cmsy10 scaled \magstep1
+\def\sececsize{1200}
+
+% Subsection fonts (10pt).
+\def\ssecnominalsize{10pt}
+\setfont\ssecrm\rmbshape{10}{1000}{OT1}
+\setfont\ssecit\itbshape{10}{1000}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1000}{OT1}
+\setfont\ssectt\ttbshape{10}{1000}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT}
+\setfont\ssecsf\sfbshape{10}{1000}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1000}{OT1}
+\font\sseci=cmmi10
+\font\ssecsy=cmsy10
+\def\ssececsize{1000}
+
+% Reduced fonts for @acronym in text (9pt).
+\def\reducednominalsize{9pt}
+\setfont\reducedrm\rmshape{9}{1000}{OT1}
+\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{900}{OT1}
+\setfont\reducedit\itshape{9}{1000}{OT1IT}
+\setfont\reducedsl\slshape{9}{1000}{OT1}
+\setfont\reducedsf\sfshape{9}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{900}{OT1}
+\setfont\reducedttsl\ttslshape{10}{900}{OT1TT}
+\font\reducedi=cmmi9
+\font\reducedsy=cmsy9
+\def\reducedecsize{0900}
+
+\divide\parskip by 2  % reduce space between paragraphs
+\textleading = 12pt   % line spacing for 10pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1}  % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
+
+% We provide the user-level command
+%   @fonttextsize 10
+% (or 11) to redefine the text font size.  pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\parseargdef\fonttextsize{%
+  \def\textsizearg{#1}%
+  %\wlog{doing @fonttextsize \textsizearg}%
+  %
+  % Set \globaldefs so that documents can use this inside @tex, since
+  % makeinfo 4.8 does not support it, but we need it nonetheless.
+  %
+ \begingroup \globaldefs=1
+  \ifx\textsizearg\xword \definetextfontsizex
+  \else \ifx\textsizearg\xiword \definetextfontsizexi
+  \else
+    \errhelp=\EMsimple
+    \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+  \fi\fi
+ \endgroup
+}
+
+%
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+  \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+  \csname #1font\endcsname  % change the current font
+}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.
+% We don't bother to reset \scriptscriptfont; awaiting user need.
+%
+\def\resetmathfonts{%
+  \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont
+  \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont
+  \textfont\ttfam=\ttfont \textfont\sffam=\sffont
+  %
+  % Fonts for superscript.  Note that the 7pt fonts are used regardless
+  % of the current font size.
+  \scriptfont0=\sevenrm \scriptfont1=\seveni \scriptfont2=\sevensy
+  \scriptfont\itfam=\sevenit \scriptfont\slfam=\sevensl
+  \scriptfont\bffam=\sevenbf \scriptfont\ttfam=\seventt
+  \scriptfont\sffam=\sevensf
+}
+
+%
+
+% The font-changing commands (all called \...fonts) redefine the meanings
+% of \STYLEfont, instead of just \STYLE.  We do this because \STYLE needs
+% to also set the current \fam for math mode.  Our \STYLE (e.g., \rm)
+% commands hardwire \STYLEfont to set the current font.
+%
+% The fonts used for \ifont are for "math italics"  (\itfont is for italics
+% in regular text).  \syfont is also used in math mode only.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower).  These relative commands are used
+% in, e.g., the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+
+\def\assignfonts#1{%
+  \expandafter\let\expandafter\rmfont\csname #1rm\endcsname
+  \expandafter\let\expandafter\itfont\csname #1it\endcsname
+  \expandafter\let\expandafter\slfont\csname #1sl\endcsname
+  \expandafter\let\expandafter\bffont\csname #1bf\endcsname
+  \expandafter\let\expandafter\ttfont\csname #1tt\endcsname
+  \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname
+  \expandafter\let\expandafter\sffont  \csname #1sf\endcsname
+  \expandafter\let\expandafter\ifont   \csname #1i\endcsname
+  \expandafter\let\expandafter\syfont  \csname #1sy\endcsname
+  \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname
+}
+
+\newif\ifrmisbold
+
+% Select smaller font size with the current style.  Used to change font size
+% in, e.g., the LaTeX logo and acronyms.  If we are using bold fonts for
+% normal roman text, also use bold fonts for roman text in the smaller size.
+\def\switchtolllsize{%
+   \expandafter\assignfonts\expandafter{\lllsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\switchtolsize{%
+   \expandafter\assignfonts\expandafter{\lsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\definefontsetatsize#1#2#3#4#5{%
+\expandafter\def\csname #1fonts\endcsname{%
+  \def\curfontsize{#1}%
+  \def\lsize{#2}\def\lllsize{#3}%
+  \csname rmisbold#5\endcsname
+  \assignfonts{#1}%
+  \resetmathfonts
+  \setleading{#4}%
+}}
+
+\definefontsetatsize{text}   {reduced}{smaller}{\textleading}{false}
+\definefontsetatsize{title}  {chap}   {subsec} {27pt}  {true}
+\definefontsetatsize{chap}   {sec}    {text}   {19pt}  {true}
+\definefontsetatsize{sec}    {subsec} {reduced}{17pt}  {true}
+\definefontsetatsize{ssec}   {text}   {small}  {15pt}  {true}
+\definefontsetatsize{reduced}{small}  {smaller}{10.5pt}{false}
+\definefontsetatsize{small}  {smaller}{smaller}{10.5pt}{false}
+\definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false}
+
+\def\titlefont#1{{\titlefonts\rm #1}}
+\let\subsecfonts = \ssecfonts
+\let\subsubsecfonts = \ssecfonts
+
+% Define these just so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts.  If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+%   8.5x11=86   smallbook=72  a4=90  a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+%   8.5x11=90+  smallbook=80  a4=90+  a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt.  So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+%   8.5x11=71  smallbook=60  a4=75  a5=58
+% --karl, 24jan03.
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\definetextfontsizexi
+
+
+\message{markup,}
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Markup style infrastructure.  \defmarkupstylesetup\INITMACRO will
+% define and register \INITMACRO to be called on markup style changes.
+% \INITMACRO can check \currentmarkupstyle for the innermost
+% style.
+
+\let\currentmarkupstyle\empty
+
+\def\setupmarkupstyle#1{%
+  \def\currentmarkupstyle{#1}%
+  \markupstylesetup
+}
+
+\let\markupstylesetup\empty
+
+\def\defmarkupstylesetup#1{%
+  \expandafter\def\expandafter\markupstylesetup
+    \expandafter{\markupstylesetup #1}%
+  \def#1%
+}
+
+% Markup style setup for left and right quotes.
+\defmarkupstylesetup\markupsetuplq{%
+  \expandafter\let\expandafter \temp
+    \csname markupsetuplq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuplqdefault \else \temp \fi
+}
+
+\defmarkupstylesetup\markupsetuprq{%
+  \expandafter\let\expandafter \temp
+    \csname markupsetuprq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuprqdefault \else \temp \fi
+}
+
+{
+\catcode`\'=\active
+\catcode`\`=\active
+
+\gdef\markupsetuplqdefault{\let`\lq}
+\gdef\markupsetuprqdefault{\let'\rq}
+
+\gdef\markupsetcodequoteleft{\let`\codequoteleft}
+\gdef\markupsetcodequoteright{\let'\codequoteright}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+%
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+%
+\let\markupsetuplqkbd     \markupsetcodequoteleft
+\let\markupsetuprqkbd     \markupsetcodequoteright
+%
+\let\markupsetuplqsamp \markupsetcodequoteleft
+\let\markupsetuprqsamp \markupsetcodequoteright
+%
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+%
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead the undirected quote from cmtt (char 0x0d).
+% The undirected quote is ugly, so don't make it the default, but it
+% works for pasting with more pdf viewers (at least evince), the
+% lilypond developers report.  xpdf does work with the regular 0x27.
+%
+\def\codequoteright{%
+  \ifmonospace
+    \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+      \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+        '%
+      \else \char'15 \fi
+    \else \char'15 \fi
+   \else
+     '%
+   \fi
+}
+%
+% and a similar option for the left quote char vs. a grave accent.
+% Modern fonts display ASCII 0x60 as a grave accent, so some people like
+% the code environments to do likewise.
+%
+\def\codequoteleft{%
+  \ifmonospace
+    \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
+      \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+        % [Knuth] pp. 380,381,391
+        % \relax disables Spanish ligatures ?` and !` of \tt font.
+        \relax`%
+      \else \char'22 \fi
+    \else \char'22 \fi
+   \else
+     \relax`%
+   \fi
+}
+
+% Commands to set the quote options.
+%
+\parseargdef\codequoteundirected{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+  \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+  \fi\fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+  \ifusingtt
+    {{\ttsl #2}\let\next=\relax}%
+    {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+  \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+  \ifx\next,%
+  \else\ifx\next-%
+  \else\ifx\next.%
+  \else\ifx\next\.%
+  \else\ifx\next\comma%
+  \else\ptexslash
+  \fi\fi\fi\fi\fi
+  \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic.  @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl.  We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+  \let\saveaftersmartic = \aftersmartic
+  \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+  \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @b, explicit bold.  Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+  \def\plainfrenchspacing{%
+    \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m
+    \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m
+    \def\endofsentencespacefactor{1000}% for @. and friends
+  }
+  \def\plainnonfrenchspacing{%
+    \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000
+    \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250
+    \def\endofsentencespacefactor{3000}% for @. and friends
+  }
+\catcode`@=\other
+\def\endofsentencespacefactor{3000}% default
+
+% @t, explicit typewriter.
+\def\t#1{%
+  {\tt \plainfrenchspacing #1}%
+  \null
+}
+
+% @samp.
+\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \plainfrenchspacing
+    #1%
+  }%
+  \null % reset spacefactor to 1000
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% (But see \codedashfinish below.)
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+%
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash. -- rms.
+{
+  \catcode`\-=\active \catcode`\_=\active
+  \catcode`\'=\active \catcode`\`=\active
+  \global\let'=\rq \global\let`=\lq  % default definitions
+  %
+  \global\def\code{\begingroup
+    \setupmarkupstyle{code}%
+    % The following should really be moved into \setupmarkupstyle handlers.
+    \catcode\dashChar=\active  \catcode\underChar=\active
+    \ifallowcodebreaks
+     \let-\codedash
+     \let_\codeunder
+    \else
+     \let-\normaldash
+     \let_\realunder
+    \fi
+    % Given -foo (with a single dash), we do not want to allow a break
+    % after the hyphen.
+    \global\let\codedashprev=\codedash
+    %
+    \codex
+  }
+  %
+  \gdef\codedash{\futurelet\next\codedashfinish}
+  \gdef\codedashfinish{%
+    \normaldash % always output the dash character itself.
+    %
+    % Now, output a discretionary to allow a line break, unless
+    % (a) the next character is a -, or
+    % (b) the preceding character is a -.
+    % E.g., given --posix, we do not want to allow a break after either -.
+    % Given --foo-bar, we do want to allow a break between the - and the b.
+    \ifx\next\codedash \else
+      \ifx\codedashprev\codedash
+      \else \discretionary{}{}{}\fi
+    \fi
+    % we need the space after the = for the case when \next itself is a
+    % space token; it would get swallowed otherwise.  As in @code{- a}.
+    \global\let\codedashprev= \next
+  }
+}
+\def\normaldash{-}
+%
+\def\codex #1{\tclose{#1}\endgroup}
+
+\def\codeunder{%
+  % this is all so @math{@code{var_name}+1} can work.  In math mode, _
+  % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+  % will therefore expand the active definition of _, which is us
+  % (inside @code that is), therefore an endless loop.
+  \ifusingtt{\ifmmode
+               \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+             \else\normalunderscore \fi
+             \discretionary{}{}{}}%
+            {\_}%
+}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__.  This is bad.
+% @allowcodebreaks provides a document-level way to turn breaking at -
+% and _ on and off.
+%
+\newif\ifallowcodebreaks  \allowcodebreakstrue
+
+\def\keywordtrue{true}
+\def\keywordfalse{false}
+
+\parseargdef\allowcodebreaks{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\keywordtrue
+    \allowcodebreakstrue
+  \else\ifx\txiarg\keywordfalse
+    \allowcodebreaksfalse
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}%
+  \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') aka @url takes an optional
+% (comma-separated) second argument specifying the text to display and
+% an optional third arg as text to display instead of (rather than in
+% addition to) the url itself.  First (mandatory) arg is the url.
+
+% TeX-only option to allow changing PDF output to show only the second
+% arg (if given), and not the url (which is then just the link target).
+\newif\ifurefurlonlylink
+
+% The main macro is \urefbreak, which allows breaking at expected
+% places within the url.  (There used to be another version, which
+% didn't support automatic breaking.)
+\def\urefbreak{\begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+%
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}% look for second arg
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        % For pdfTeX and LuaTeX
+        \ifurefurlonlylink
+          % PDF plus option to not display url, show just arg
+          \unhbox0
+        \else
+          % PDF, normally display both arg and url for consistency,
+          % visibility, if the pdf is eventually used to print, etc.
+          \unhbox0\ (\urefcode{#1})%
+        \fi
+      \else
+        \ifx\XeTeXrevision\thisisundefined
+          \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+        \else
+          % For XeTeX
+          \ifurefurlonlylink
+            % PDF plus option to not display url, show just arg
+            \unhbox0
+          \else
+            % PDF, normally display both arg and url for consistency,
+            % visibility, if the pdf is eventually used to print, etc.
+            \unhbox0\ (\urefcode{#1})%
+          \fi
+        \fi
+      \fi
+    \else
+      \urefcode{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+  \catcode`\&=\active \catcode`\.=\active
+  \catcode`\#=\active \catcode`\?=\active
+  \catcode`\/=\active
+}
+{
+  \urefcatcodes
+  %
+  \global\def\urefcode{\begingroup
+    \setupmarkupstyle{code}%
+    \urefcatcodes
+    \let&\urefcodeamp
+    \let.\urefcodedot
+    \let#\urefcodehash
+    \let?\urefcodequest
+    \let/\urefcodeslash
+    \codex
+  }
+  %
+  % By default, they are just regular characters.
+  \global\def&{\normalamp}
+  \global\def.{\normaldot}
+  \global\def#{\normalhash}
+  \global\def?{\normalquest}
+  \global\def/{\normalslash}
+}
+
+\def\urefcodeamp{\urefprebreak \&\urefpostbreak}
+\def\urefcodedot{\urefprebreak .\urefpostbreak}
+\def\urefcodehash{\urefprebreak \#\urefpostbreak}
+\def\urefcodequest{\urefprebreak ?\urefpostbreak}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+  \catcode`\/=\active
+  \global\def\urefcodeslashfinish{%
+    \urefprebreak \slashChar
+    % Allow line break only after the final / in a sequence of
+    % slashes, to avoid line break between the slashes in http://.
+    \ifx\next/\else \urefpostbreak \fi
+  }
+}
+
+% By default we'll break after the special characters, but some people like to
+% break before the special chars, so allow that.  Also allow no breaking at
+% all, for manual control.
+%
+\parseargdef\urefbreakstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\wordnone
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordbefore
+    \def\urefprebreak{\urefallowbreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordafter
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\urefallowbreak}
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+% Allow a ragged right output to aid breaking long URL's.  There can
+% be a break at the \allowbreak with no extra glue (if the existing stretch in
+% the line is sufficent), a break at the \penalty100 with extra glue added
+% at the end of the line, or no break at all here.
+%   Changing the value of the penalty and/or the amount of stretch affects how
+% preferrable one choice is over the other.
+\def\urefallowbreak{%
+  \allowbreak
+  \hskip 0pt plus 2 em\relax
+  \penalty300
+  \hskip 0pt plus -2 em\relax
+}
+
+\urefbreakstyle after
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdforxetex
+  \def\email#1{\doemail#1,,\finish}
+  \def\doemail#1,#2,#3\finish{\begingroup
+    \unsepspaces
+    \pdfurl{mailto:#1}%
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+    \endlink
+  \endgroup}
+\else
+  \let\email=\uref
+\fi
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\txiarg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\txiarg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @kbdinputstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#1#2#3\par{%
+  \def\one{#1}\def\three{#3}\def\threex{??}%
+  \ifx\one\xkey\ifx\threex\three \key{#2}%
+  \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+  \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+}
+
+% definition of @key that produces a lozenge.  Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+%  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+%    \vbox{\hrule\kern-0.4pt
+%     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+%    \kern-0.4pt\hrule}%
+%  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge.  If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle.  But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setupmarkupstyle{key}%
+  \nohyphenation
+  \ifmonospace\else\tt\fi
+  #1}\null}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow   (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+  {\switchtolsize #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+  {\plainfrenchspacing #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}.  So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+  \catcode`\_ = \active
+  \gdef\mathunderscore{%
+    \catcode`\_=\active
+    \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+  }
+}
+% Another complication: we want \\ (and @\) to output a math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+  \ifmmode\else % only go into math if not in math mode already
+    \tex
+    \mathunderscore
+    \let\\ = \mathbackslash
+    \mathactive
+    % make the texinfo accent commands work in math mode
+    \let\"=\ddot
+    \let\'=\acute
+    \let\==\bar
+    \let\^=\hat
+    \let\`=\grave
+    \let\u=\breve
+    \let\v=\check
+    \let\~=\tilde
+    \let\dotaccent=\dot
+    % have to provide another name for sup operator
+    \let\mathopsup=\sup
+  $\expandafter\finishmath\fi
+}
+\def\finishmath#1{#1$\endgroup}  % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+  \catcode`^ = \active
+  \catcode`< = \active
+  \catcode`> = \active
+  \catcode`+ = \active
+  \catcode`' = \active
+  \gdef\mathactive{%
+    \let^ = \ptexhat
+    \let< = \ptexless
+    \let> = \ptexgtr
+    \let+ = \ptexplus
+    \let' = \ptexquoteright
+  }
+}
+
+% for @sub and @sup, if in math mode, just do a normal sub/superscript.
+% If in text, use math to place as sub/superscript, but switch
+% into text mode, with smaller fonts.  This is a different font than the
+% one used for real math sub/superscripts (8pt vs. 7pt), but let's not
+% fix it (significant additions to font machinery) until someone notices.
+%
+\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi}
+\def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}%
+%
+\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi}
+\def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}%
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+%
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+%
+% @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if
+% FMTNAME is tex, else ELSE-TEXT.
+\long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish}
+\long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi
+}
+%
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely.  Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored.  But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too.  We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+%
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+  \def\inlinerawname{#1}%
+  \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+  \endgroup % close group opened by \tex.
+}
+
+% @inlineifset{VAR, TEXT} expands TEXT if VAR is @set.
+%
+\long\def\inlineifset#1{\doinlineifset #1,\finish}
+\long\def\doinlineifset#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax
+  \else\ignorespaces#2\fi
+}
+
+% @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set.
+%
+\long\def\inlineifclear#1{\doinlineifclear #1,\finish}
+\long\def\doinlineifclear#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+\def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}}
+\def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}}
+\let\{=\lbracechar
+\let\}=\rbracechar
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi
+  \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence.  (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo.  Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+  L\kern-.36em
+  {\setbox0=\hbox{T}%
+   \vbox to \ht0{\hbox{%
+     \ifx\textnominalsize\xwordpt
+       % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX.
+       % Revert to plain's \scriptsize, which is 7pt.
+       \count255=\the\fam $\fam\count255 \scriptstyle A$%
+     \else
+       % For 11pt, we can use our lllsize.
+       \switchtolllsize A%
+     \fi
+     }%
+     \vss
+  }}%
+  \kern-.15em
+  \TeX
+}
+
+% Some math mode symbols.  Define \ensuremath to switch into math mode
+% unless we are already there.  Expansion tricks may not be needed here,
+% but safer, and can't hurt.
+\def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi}
+\def\ensuredmath#1{$\relax#1$}
+%
+\def\bullet{\ensuremath\ptexbullet}
+\def\geq{\ensuremath\ge}
+\def\leq{\ensuremath\le}
+\def\minus{\ensuremath-}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in the cm
+% typewriter fonts as three actual period characters; on the other hand,
+% in other typewriter fonts three periods are wider than 1.5em.  So do
+% whichever is larger.
+%
+\def\dots{%
+  \leavevmode
+  \setbox0=\hbox{...}% get width of three periods
+  \ifdim\wd0 > 1.5em
+    \dimen0 = \wd0
+  \else
+    \dimen0 = 1.5em
+  \fi
+  \hbox to \dimen0{%
+    \hskip 0pt plus.25fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+  \dots
+  \spacefactor=\endofsentencespacefactor
+}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, they should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}}
+\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\ttfont \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{%
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\it\$}}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that.  The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math.  Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+  % We set the font at each command, rather than predefining it in
+  % \textfonts and the other font-switching commands, so that
+  % installations which never need the symbol don't have to have the
+  % font installed.
+  %
+  % There is only one designed size (nominal 10pt), so we always scale
+  % that to the current nominal size.
+  %
+  % By the way, simply using "at 1em" works for cmr10 and the like, but
+  % does not work for cmbx10 and other extended/shrunken fonts.
+  %
+  \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+  %
+  \ifx\curfontstyle\bfstylename
+    % bold:
+    \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+  \else
+    % regular:
+    \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+  \fi
+  \thiseurofont
+}
+
+% Glyphs from the EC fonts.  We don't use \let for the aliases, because
+% sometimes we redefine the original macro, and the alias should reflect
+% the redefinition.
+%
+% Use LaTeX names for the Icelandic letters.
+\def\DH{{\ecfont \char"D0}} % Eth
+\def\dh{{\ecfont \char"F0}} % eth
+\def\TH{{\ecfont \char"DE}} % Thorn
+\def\th{{\ecfont \char"FE}} % thorn
+%
+\def\guillemetleft{{\ecfont \char"13}}
+\def\guillemotleft{\guillemetleft}
+\def\guillemetright{{\ecfont \char"14}}
+\def\guillemotright{\guillemetright}
+\def\guilsinglleft{{\ecfont \char"0E}}
+\def\guilsinglright{{\ecfont \char"0F}}
+\def\quotedblbase{{\ecfont \char"12}}
+\def\quotesinglbase{{\ecfont \char"0D}}
+%
+% This positioning is not perfect (see the ogonek LaTeX package), but
+% we have the precomposed glyphs for the most common cases.  We put the
+% tests to use those glyphs in the single \ogonek macro so we have fewer
+% dummy definitions to worry about for index entries, etc.
+%
+% ogonek is also used with other letters in Lithuanian (IOU), but using
+% the precomposed glyphs for those is not so easy since they aren't in
+% the same EC font.
+\def\ogonek#1{{%
+  \def\temp{#1}%
+  \ifx\temp\macrocharA\Aogonek
+  \else\ifx\temp\macrochara\aogonek
+  \else\ifx\temp\macrocharE\Eogonek
+  \else\ifx\temp\macrochare\eogonek
+  \else
+    \ecfont \setbox0=\hbox{#1}%
+    \ifdim\ht0=1ex\accent"0C #1%
+    \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}%
+    \fi
+  \fi\fi\fi\fi
+  }%
+}
+\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A}
+\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a}
+\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E}
+\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e}
+%
+% Use the European Computer Modern fonts (cm-super in outline format)
+% for non-CM glyphs.  That is ec* for regular text and tc* for the text
+% companion symbols (LaTeX TS1 encoding).  Both are part of the ec
+% package and follow the same conventions.
+%
+\def\ecfont{\etcfont{e}}
+\def\tcfont{\etcfont{t}}
+%
+\def\etcfont#1{%
+  % We can't distinguish serif/sans and italic/slanted, but this
+  % is used for crude hacks anyway (like adding French and German
+  % quotes to documents typeset with CM, where we lose kerning), so
+  % hopefully nobody will notice/care.
+  \edef\ecsize{\csname\curfontsize ecsize\endcsname}%
+  \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}%
+  \ifmonospace
+    % typewriter:
+    \font\thisecfont = #1ctt\ecsize \space at \nominalsize
+  \else
+    \ifx\curfontstyle\bfstylename
+      % bold:
+      \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize
+    \else
+      % regular:
+      \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+    \fi
+  \fi
+  \thisecfont
+}
+
+% @registeredsymbol - R in a circle.  The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+  $^{{\ooalign{\hfil\raise.07ex\hbox{\switchtolllsize R}%
+               \hfil\crcr\Orb}}%
+    }$%
+}
+
+% @textdegree - the normal degrees sign.
+%
+\def\textdegree{$^\circ$}
+
+% Laurent Siebenmann reports \Orb undefined with:
+%  Textures 1.7.7 (preloaded format=plain 93.10.14)  (68K)  16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\thisisundefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quotedblleft="5C
+\chardef\quotedblright=`\"
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% @setcontentsaftertitlepage used to do an implicit @contents or
+% @shortcontents after @end titlepage, but it is now obsolete.
+\def\setcontentsaftertitlepage{%
+  \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @contents command if you want the contents
+              after the title page.}}%
+\def\setshortcontentsaftertitlepage{%
+  \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @shortcontents and @contents commands if you
+              want the contents after the title page.}}%
+
+\parseargdef\shorttitlepage{%
+  \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+  \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+  % Open one extra group, as we want to close it in the middle of \Etitlepage.
+  \begingroup
+    \parindent=0pt \textfonts
+    % Leave some space at the very top of the page.
+    \vglue\titlepagetopglue
+    % No rule at page bottom unless we print one at the top with @title.
+    \finishedtitlepagetrue
+    %
+    % Most title ``pages'' are actually two pages long, with space
+    % at the top of the second.  We don't want the ragged left on the second.
+    \let\oldpage = \page
+    \def\page{%
+      \iffinishedtitlepage\else
+        \finishtitlepage
+      \fi
+      \let\page = \oldpage
+      \page
+      \null
+    }%
+}
+
+\def\Etitlepage{%
+    \iffinishedtitlepage\else
+       \finishtitlepage
+    \fi
+    % It is important to do the page break before ending the group,
+    % because the headline and footline are only empty inside the group.
+    % If we use the new definition of \page, we always get a blank page
+    % after the title page, which we certainly don't want.
+    \oldpage
+  \endgroup
+  %
+  % Need this before the \...aftertitlepage checks so that if they are
+  % in effect the toc pages will come out with page numbers.
+  \HEADINGSon
+}
+
+\def\finishtitlepage{%
+  \vskip4pt \hrule height 2pt width \hsize
+  \vskip\titlepagebottomglue
+  \finishedtitlepagetrue
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right.  This should be used
+% inside a \vbox, and fonts need to be set appropriately first. \par should
+% be specified before the end of the \vbox, since a vbox is a group.
+%
+\def\raggedtitlesettings{%
+  \rm
+  \hyphenpenalty=10000
+  \parindent=0pt
+  \tolerance=5000
+  \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\rmfont
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+  \checkenv\titlepage
+  \vbox{\titlefonts \raggedtitlesettings #1\par}%
+  % print a rule at the page bottom also.
+  \finishedtitlepagefalse
+  \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+  \checkenv\titlepage
+  {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+  \def\temp{\quotation}%
+  \ifx\thisenv\temp
+    \def\quotationauthor{#1}% printed in \Equotation.
+  \else
+    \checkenv\titlepage
+    \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+    {\secfonts\rm \leftline{#1}}%
+  \fi
+}
+
+
+% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make \makeheadline and \makefootline in Plain TeX use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\txipageheight by -12pt
+  \global\advance\vsize by -12pt
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+% @evenheadingmarks top     \thischapter <- chapter at the top of a page
+% @evenheadingmarks bottom  \thischapter <- chapter at the bottom of a page
+%
+% The same set of arguments for:
+%
+% @oddheadingmarks
+% @evenfootingmarks
+% @oddfootingmarks
+% @everyheadingmarks
+% @everyfootingmarks
+
+% These define \getoddheadingmarks, \getevenheadingmarks,
+% \getoddfootingmarks, and \getevenfootingmarks, each to one of
+% \gettopheadingmarks, \getbottomheadingmarks.
+%
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1}
+                          \headingmarks{odd}{heading}{#1} }
+\parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1}
+                          \headingmarks{odd}{footing}{#1} }
+% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
+\def\headingmarks#1#2#3 {%
+  \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname
+  \global\expandafter\let\csname get#1#2marks\endcsname \temp
+}
+
+\everyheadingmarks bottom
+\everyfootingmarks bottom
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\parseargdef\headings{\csname HEADINGS#1\endcsname}
+
+\def\headingsoff{% non-global headings elimination
+  \evenheadline={\hfil}\evenfootline={\hfil}%
+   \oddheadline={\hfil}\oddfootline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff  % it's the default
+
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapterheading\hfil\folio}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapterheading\hfil\folio}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\thisisundefined
+\def\today{%
+  \number\day\space
+  \ifcase\month
+  \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+  \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+  \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+  \fi
+  \space\number\year}
+\fi
+
+% @settitle line...  specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemindicate{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil\relax
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  However, if
+    % what follows is an environment such as @example, there will be no
+    % \parskip glue; then the negative vskip we just inserted would
+    % cause the example and the item to crash together.  So we use this
+    % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+    % \parskip glue after all.  Section titles are handled this way also.
+    %
+    \penalty 10001
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+  \let\itemindex\gobble
+  \tablecheck{table}%
+}
+\envdef\ftable{%
+  \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+  \tablecheck{ftable}%
+}
+\envdef\vtable{%
+  \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+  \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+  \ifnum \the\catcode`\^^M=\active
+    \endgroup
+    \errmessage{This command won't work in this context; perhaps the problem is
+      that we are \inenvironment\thisenv}%
+    \def\next{\doignore{#1}}%
+  \else
+    \let\next\tablex
+  \fi
+  \next
+}
+\def\tablex#1{%
+  \def\itemindicate{#1}%
+  \parsearg\tabley
+}
+\def\tabley#1{%
+  {%
+    \makevalueexpandable
+    \edef\temp{\noexpand\tablez #1\space\space\space}%
+    \expandafter
+  }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+  \aboveenvbreak
+  \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+  \ifnum 0#2>0 \tableindent=#2\mil \fi
+  \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+  \itemmax=\tableindent
+  \advance \itemmax by -\itemmargin
+  \advance \leftskip by \tableindent
+  \exdentamount=\tableindent
+  \parindent = 0pt
+  \parskip = \smallskipamount
+  \ifdim \parskip=0pt \parskip=2pt \fi
+  \let\item = \internalBitem
+  \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+  \aboveenvbreak
+  \itemmax=\itemindent
+  \advance\itemmax by -\itemmargin
+  \advance\leftskip by \itemindent
+  \exdentamount=\itemindent
+  \parindent=0pt
+  \parskip=\smallskipamount
+  \ifdim\parskip=0pt \parskip=2pt \fi
+  %
+  % Try typesetting the item mark so that if the document erroneously says
+  % something like @itemize @samp (intending @table), there's an error
+  % right away at the @itemize.  It's not the best error message in the
+  % world, but it's better than leaving it to the @item.  This means if
+  % the user wants an empty mark, they have to say @w{} not just @w.
+  \def\itemcontents{#1}%
+  \setbox0 = \hbox{\itemcontents}%
+  %
+  % @itemize with no arg is equivalent to @itemize @bullet.
+  \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+  %
+  \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+  \advance\itemno by 1  % for enumerations
+  {\let\par=\endgraf \smallbreak}% reasonable place to break
+  {%
+   % If the document has an @itemize directly after a section title, a
+   % \nobreak will be last on the list, and \sectionheading will have
+   % done a \vskip-\parskip.  In that case, we don't want to zero
+   % parskip, or the item text will crash with the heading.  On the
+   % other hand, when there is normal text preceding the item (as there
+   % usually is), we do want to zero parskip, or there would be too much
+   % space.  In that case, we won't have a \nobreak before.  At least
+   % that's the theory.
+   \ifnum\lastpenalty<10000 \parskip=0in \fi
+   \noindent
+   \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+   %
+   \ifinner\else
+     \vadjust{\penalty 1200}% not good to break after first line of item.
+   \fi
+   % We can be in inner vertical mode in a footnote, although an
+   % @itemize looks awful there.
+  }%
+  \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call \doitemize, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \doitemize{#1.}\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble.  Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+%   @multitable @columnfractions .25 .3 .45
+%   @item ...
+%
+%   Numbers following @columnfractions are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab do not need to be on their own lines, but it will not hurt
+% if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item
+%   first col stuff
+%   @tab
+%   second col stuff
+%   @tab
+%   third col
+%   @item first col stuff @tab second col stuff
+%   @tab Many paragraphs of text may be used in any column.
+%
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+%                                                            to baseline.
+%   0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the @columnfraction, usually a decimal number like .5, but might
+% be just 1.  We just use it, whatever it is.
+%
+\def\pickupwholefraction#1 {%
+  \global\advance\colcount by 1
+  \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}%
+  \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+  \def\firstarg{#1}%
+  \ifx\firstarg\xendsetuptable
+    \let\go = \relax
+  \else
+    \ifx\firstarg\xcolumnfractions
+      \global\setpercenttrue
+    \else
+      \ifsetpercent
+         \let\go\pickupwholefraction
+      \else
+         \global\advance\colcount by 1
+         \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a
+                   % separator; typically that is always in the input, anyway.
+         \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+      \fi
+    \fi
+    \ifx\go\pickupwholefraction
+      % Put the argument back for the \pickupwholefraction call, so
+      % we'll always have a period there to be parsed.
+      \def\go{\pickupwholefraction#1}%
+    \else
+      \let\go = \setuptable
+    \fi%
+  \fi
+  \go
+}
+
+% multitable-only commands.
+%
+% @headitem starts a heading row, which we typeset in bold.  Assignments
+% have to be global since we are inside the implicit group of an
+% alignment entry.  \everycr below resets \everytab so we don't have to
+% undo it ourselves.
+\def\headitemfont{\b}% for people to use in the template row; not changeable
+\def\headitem{%
+  \checkenv\multitable
+  \crcr
+  \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings
+  \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+  \the\everytab % for the first item
+}%
+%
+% default for tables with no headings.
+\let\headitemcrhook=\relax
+%
+% A \tab used to include \hskip1sp.  But then the space in a template
+% line is not enough.  That is bad.  So let's go back to just `&' until
+% we again encounter the problem the 1sp was intended to solve.
+%                                      --karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab  % insert after every tab.
+%
+\envdef\multitable{%
+  \vskip\parskip
+  \startsavinginserts
+  %
+  % @item within a multitable starts a normal row.
+  % We use \def instead of \let so that if one of the multitable entries
+  % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+  % \endtemplate) expanding \doitemize.
+  \def\item{\crcr}%
+  %
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  %
+  \everycr = {%
+    \noalign{%
+      \global\everytab={}% Reset from possible headitem.
+      \global\colcount=0 % Reset the column counter.
+      %
+      % Check for saved footnotes, etc.:
+      \checkinserts
+      %
+      % Perhaps a \nobreak, then reset:
+      \headitemcrhook
+      \global\let\headitemcrhook=\relax
+    }%
+  }%
+  %
+  \parsearg\domultitable
+}
+\def\domultitable#1{%
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup &%
+    \global\advance\colcount by 1
+    \multistrut
+    \vtop{%
+      % Use the current \colcount to find the correct column width:
+      \hsize=\expandafter\csname col\the\colcount\endcsname
+      %
+      % In order to keep entries from bumping into each other
+      % we will add a \leftskip of \multitablecolspace to all columns after
+      % the first one.
+      %
+      % If a template has been used, we will add \multitablecolspace
+      % to the width of each template entry.
+      %
+      % If the user has set preamble in terms of percent of \hsize we will
+      % use that dimension as the width of the column, and the \leftskip
+      % will keep entries from bumping into each other.  Table will start at
+      % left margin and final column will justify at right margin.
+      %
+      % Make sure we don't inherit \rightskip from the outer environment.
+      \rightskip=0pt
+      \ifnum\colcount=1
+       % The first column will be indented with the surrounding text.
+       \advance\hsize by\leftskip
+      \else
+       \ifsetpercent \else
+         % If user has not set preamble in terms of percent of \hsize
+         % we will advance \hsize by \multitablecolspace.
+         \advance\hsize by \multitablecolspace
+       \fi
+       % In either case we will make \leftskip=\multitablecolspace:
+      \leftskip=\multitablecolspace
+      \fi
+      % Ignoring space at the beginning and end avoids an occasional spurious
+      % blank line, when TeX decides to break the line at the space before the
+      % box from the multistrut, so the strut ends up on a line by itself.
+      % For example:
+      % @multitable @columnfractions .11 .89
+      % @item @code{#}
+      % @tab Legal holiday which is valid in major parts of the whole country.
+      % Is automatically provided with highlighting sequences respectively
+      % marking characters.
+      \noindent\ignorespaces##\unskip\multistrut
+    }\cr
+}
+\def\Emultitable{%
+  \crcr
+  \egroup % end the \halign
+  \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+  \def\multistrut{\strut}% just use the standard line spacing
+  %
+  % Compute \multitablelinespace (if not defined by user) for use in
+  % \multitableparskip calculation.  We used define \multistrut based on
+  % this, but (ironically) that caused the spacing to be off.
+  % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+% Test to see if parskip is larger than space between lines of
+% table. If not, do nothing.
+%        If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed.  They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested.  But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+  \expandafter\let\csname #1\endcsname = \relax
+  \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+  % Scan in ``verbatim'' mode:
+  \obeylines
+  \catcode`\@ = \other
+  \catcode`\{ = \other
+  \catcode`\} = \other
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \spaceisspace
+  %
+  % Count number of #1's that we've seen.
+  \doignorecount = 0
+  %
+  % Swallow text until we reach the matching `@end #1'.
+  \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+  \obeylines %
+  %
+  \gdef\dodoignore#1{%
+    % #1 contains the command name as a string, e.g., `ifinfo'.
+    %
+    % Define a command to find the next `@end #1'.
+    \long\def\doignoretext##1^^M@end #1{%
+      \doignoretextyyy##1^^M@#1\_STOP_}%
+    %
+    % And this command to find another #1 command, at the beginning of a
+    % line.  (Otherwise, we would consider a line `@c @ifset', for
+    % example, to count as an @ifset for nesting.)
+    \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+    %
+    % And now expand that command.
+    \doignoretext ^^M%
+  }%
+}
+
+\def\doignoreyyy#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty                      % Nothing found.
+    \let\next\doignoretextzzz
+  \else                                        % Found a nested condition, ...
+    \advance\doignorecount by 1
+    \let\next\doignoretextyyy          % ..., look for another.
+    % If we're here, #1 ends with ^^M\ifinfo (for example).
+  \fi
+  \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+  \ifnum\doignorecount = 0     % We have just found the outermost @end.
+    \let\next\enddoignore
+  \else                                % Still inside a nested condition.
+    \advance\doignorecount by -1
+    \let\next\doignoretext      % Look for the next @end.
+  \fi
+  \next
+}
+
+% Finish off ignored text.
+{ \obeylines%
+  % Ignore anything after the last `@end #1'; this matters in verbatim
+  % environments, where otherwise the newline after an ignored conditional
+  % would result in a blank line in the output.
+  \gdef\enddoignore#1^^M{\endgroup\ignorespaces}%
+}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  {%
+    \makevalueexpandable
+    \def\temp{#2}%
+    \edef\next{\gdef\makecsname{SET#1}}%
+    \ifx\temp\empty
+      \next{}%
+    \else
+      \setzzz#2\endsetzzz
+    \fi
+  }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+  {%
+    \makevalueexpandable
+    \global\expandafter\let\csname SET#1\endcsname=\relax
+  }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+  \catcode`\-=\active \catcode`\_=\active
+  %
+  \gdef\makevalueexpandable{%
+    \let\value = \expandablevalue
+    % We don't want these characters active, ...
+    \catcode`\-=\other \catcode`\_=\other
+    % ..., but we might end up with active ones in the argument if
+    % we're called from @code, as @code{@value{foo-bar_}}, though.
+    % So \let them to their normal equivalents.
+    \let-\normaldash \let_\normalunderscore
+  }
+}
+
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+    \message{Variable `#1', used in @value, is not set.}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% Like \expandablevalue, but completely expandable (the \message in the
+% definition above operates at the execution level of TeX).  Used when
+% writing to auxiliary files, due to the expansion that \write does.
+% If flag is undefined, pass through an unexpanded @value command: maybe it
+% will be set by the time it is read back in.
+%
+% NB flag names containing - or _ may not work here.
+\def\dummyvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \string\value{#1}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% Used for @value's in index entries to form the sort key: expand the @value
+% if possible, otherwise sort late.
+\def\indexnofontsvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    ZZZZZZZ%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get the special treatment we need for `@end ifset,' we call
+% \makecond and then redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+  {%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname SET#2\endcsname\relax
+      #1% If not set, redefine \next.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end executes the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined.  We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+%
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname #2\endcsname\relax
+      #1% If not defined, \let\next as above.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+  \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named IX.
+% It automatically defines \IXindex such that
+% \IXindex ...rest of line... puts an entry in the index IX.
+% It also defines \IXindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is IX.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}%
+}
+
+% The default indices:
+\newindex{cp}%      concepts,
+\newcodeindex{fn}%  functions,
+\newcodeindex{vr}%  variables,
+\newcodeindex{tp}%  types,
+\newcodeindex{ky}%  keys
+\newcodeindex{pg}%  and programs.
+
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+  \requireopenindexfile{#3}%
+  % redefine \fooindfile:
+  \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+  \expandafter\let\csname#2indfile\endcsname=\temp
+  % redefine \fooindex:
+  \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all index macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is the two-letter name of the index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx}
+\def\doindexxxx #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx}
+\def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}}
+
+
+% Used for the aux, toc and index files to prevent expansion of Texinfo
+% commands.
+%
+\def\atdummies{%
+  \definedummyletter\@%
+  \definedummyletter\ %
+  \definedummyletter\{%
+  \definedummyletter\}%
+  \definedummyletter\&%
+  %
+  % Do the redefinitions.
+  \definedummies
+  \otherbackslash
+}
+
+% \definedummyword defines \#1 as \string\#1\space, thus effectively
+% preventing its expansion.  This is used only for control words,
+% not control letters, because the \space would be incorrect for
+% control characters, but is needed to separate the control word
+% from whatever follows.
+%
+% These can be used both for control words that take an argument and
+% those that do not.  If it is followed by {arg} in the input, then
+% that will dutifully get written to the index (or wherever).
+%
+% For control letters, we have \definedummyletter, which omits the
+% space.
+%
+\def\definedummyword  #1{\def#1{\string#1\space}}%
+\def\definedummyletter#1{\def#1{\string#1}}%
+\let\definedummyaccent\definedummyletter
+
+% Called from \atdummies to prevent the expansion of commands.
+%
+\def\definedummies{%
+  %
+  \let\commondummyword\definedummyword
+  \let\commondummyletter\definedummyletter
+  \let\commondummyaccent\definedummyaccent
+  \commondummiesnofonts
+  %
+  \definedummyletter\_%
+  \definedummyletter\-%
+  %
+  % Non-English letters.
+  \definedummyword\AA
+  \definedummyword\AE
+  \definedummyword\DH
+  \definedummyword\L
+  \definedummyword\O
+  \definedummyword\OE
+  \definedummyword\TH
+  \definedummyword\aa
+  \definedummyword\ae
+  \definedummyword\dh
+  \definedummyword\exclamdown
+  \definedummyword\l
+  \definedummyword\o
+  \definedummyword\oe
+  \definedummyword\ordf
+  \definedummyword\ordm
+  \definedummyword\questiondown
+  \definedummyword\ss
+  \definedummyword\th
+  %
+  % Although these internal commands shouldn't show up, sometimes they do.
+  \definedummyword\bf
+  \definedummyword\gtr
+  \definedummyword\hat
+  \definedummyword\less
+  \definedummyword\sf
+  \definedummyword\sl
+  \definedummyword\tclose
+  \definedummyword\tt
+  %
+  \definedummyword\LaTeX
+  \definedummyword\TeX
+  %
+  % Assorted special characters.
+  \definedummyword\ampchar
+  \definedummyword\atchar
+  \definedummyword\arrow
+  \definedummyword\backslashchar
+  \definedummyword\bullet
+  \definedummyword\comma
+  \definedummyword\copyright
+  \definedummyword\registeredsymbol
+  \definedummyword\dots
+  \definedummyword\enddots
+  \definedummyword\entrybreak
+  \definedummyword\equiv
+  \definedummyword\error
+  \definedummyword\euro
+  \definedummyword\expansion
+  \definedummyword\geq
+  \definedummyword\guillemetleft
+  \definedummyword\guillemetright
+  \definedummyword\guilsinglleft
+  \definedummyword\guilsinglright
+  \definedummyword\lbracechar
+  \definedummyword\leq
+  \definedummyword\mathopsup
+  \definedummyword\minus
+  \definedummyword\ogonek
+  \definedummyword\pounds
+  \definedummyword\point
+  \definedummyword\print
+  \definedummyword\quotedblbase
+  \definedummyword\quotedblleft
+  \definedummyword\quotedblright
+  \definedummyword\quoteleft
+  \definedummyword\quoteright
+  \definedummyword\quotesinglbase
+  \definedummyword\rbracechar
+  \definedummyword\result
+  \definedummyword\sub
+  \definedummyword\sup
+  \definedummyword\textdegree
+  %
+  \definedummyword\subentry
+  %
+  % We want to disable all macros so that they are not expanded by \write.
+  \macrolist
+  \let\value\dummyvalue
+  %
+  \normalturnoffactive
+}
+
+% \commondummiesnofonts: common to \definedummies and \indexnofonts.
+% Define \commondummyletter, \commondummyaccent and \commondummyword before
+% using.  Used for accents, font commands, and various control letters.
+%
+\def\commondummiesnofonts{%
+  % Control letters and accents.
+  \commondummyletter\!%
+  \commondummyaccent\"%
+  \commondummyaccent\'%
+  \commondummyletter\*%
+  \commondummyaccent\,%
+  \commondummyletter\.%
+  \commondummyletter\/%
+  \commondummyletter\:%
+  \commondummyaccent\=%
+  \commondummyletter\?%
+  \commondummyaccent\^%
+  \commondummyaccent\`%
+  \commondummyaccent\~%
+  \commondummyword\u
+  \commondummyword\v
+  \commondummyword\H
+  \commondummyword\dotaccent
+  \commondummyword\ogonek
+  \commondummyword\ringaccent
+  \commondummyword\tieaccent
+  \commondummyword\ubaraccent
+  \commondummyword\udotaccent
+  \commondummyword\dotless
+  %
+  % Texinfo font commands.
+  \commondummyword\b
+  \commondummyword\i
+  \commondummyword\r
+  \commondummyword\sansserif
+  \commondummyword\sc
+  \commondummyword\slanted
+  \commondummyword\t
+  %
+  % Commands that take arguments.
+  \commondummyword\abbr
+  \commondummyword\acronym
+  \commondummyword\anchor
+  \commondummyword\cite
+  \commondummyword\code
+  \commondummyword\command
+  \commondummyword\dfn
+  \commondummyword\dmn
+  \commondummyword\email
+  \commondummyword\emph
+  \commondummyword\env
+  \commondummyword\file
+  \commondummyword\image
+  \commondummyword\indicateurl
+  \commondummyword\inforef
+  \commondummyword\kbd
+  \commondummyword\key
+  \commondummyword\math
+  \commondummyword\option
+  \commondummyword\pxref
+  \commondummyword\ref
+  \commondummyword\samp
+  \commondummyword\strong
+  \commondummyword\tie
+  \commondummyword\U
+  \commondummyword\uref
+  \commondummyword\url
+  \commondummyword\var
+  \commondummyword\verb
+  \commondummyword\w
+  \commondummyword\xref
+}
+
+\let\indexlbrace\relax
+\let\indexrbrace\relax
+\let\indexatchar\relax
+\let\indexbackslash\relax
+
+{\catcode`\@=0
+\catcode`\\=13
+  @gdef@backslashdisappear{@def\{}}
+}
+
+{
+\catcode`\<=13
+\catcode`\-=13
+\catcode`\`=13
+  \gdef\indexnonalnumdisappear{%
+    \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else
+      % @set txiindexlquoteignore makes us ignore left quotes in the sort term.
+      % (Introduced for FSFS 2nd ed.)
+      \let`=\empty
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else
+      \backslashdisappear
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else
+      \def-{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else
+      \def<{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else
+      \def\@{}%
+    \fi
+  }
+
+  \gdef\indexnonalnumreappear{%
+    \let-\normaldash
+    \let<\normalless
+  }
+}
+
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names.  It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+  % Accent commands should become @asis.
+  \def\commondummyaccent##1{\let##1\asis}%
+  % We can just ignore other control letters.
+  \def\commondummyletter##1{\let##1\empty}%
+  % All control words become @asis by default; overrides below.
+  \let\commondummyword\commondummyaccent
+  \commondummiesnofonts
+  %
+  % Don't no-op \tt, since it isn't a user-level command
+  % and is used in the definitions of the active chars like <, >, |, etc.
+  % Likewise with the other plain tex font commands.
+  %\let\tt=\asis
+  %
+  \def\ { }%
+  \def\@{@}%
+  \def\_{\normalunderscore}%
+  \def\-{}% @- shouldn't affect sorting
+  %
+  \uccode`\1=`\{ \uppercase{\def\{{1}}%
+  \uccode`\1=`\} \uppercase{\def\}{1}}%
+  \let\lbracechar\{%
+  \let\rbracechar\}%
+  %
+  % Non-English letters.
+  \def\AA{AA}%
+  \def\AE{AE}%
+  \def\DH{DZZ}%
+  \def\L{L}%
+  \def\OE{OE}%
+  \def\O{O}%
+  \def\TH{TH}%
+  \def\aa{aa}%
+  \def\ae{ae}%
+  \def\dh{dzz}%
+  \def\exclamdown{!}%
+  \def\l{l}%
+  \def\oe{oe}%
+  \def\ordf{a}%
+  \def\ordm{o}%
+  \def\o{o}%
+  \def\questiondown{?}%
+  \def\ss{ss}%
+  \def\th{th}%
+  %
+  \def\LaTeX{LaTeX}%
+  \def\TeX{TeX}%
+  %
+  % Assorted special characters.  \defglyph gives the control sequence a
+  % definition that removes the {} that follows its use.
+  \defglyph\atchar{@}%
+  \defglyph\arrow{->}%
+  \defglyph\bullet{bullet}%
+  \defglyph\comma{,}%
+  \defglyph\copyright{copyright}%
+  \defglyph\dots{...}%
+  \defglyph\enddots{...}%
+  \defglyph\equiv{==}%
+  \defglyph\error{error}%
+  \defglyph\euro{euro}%
+  \defglyph\expansion{==>}%
+  \defglyph\geq{>=}%
+  \defglyph\guillemetleft{<<}%
+  \defglyph\guillemetright{>>}%
+  \defglyph\guilsinglleft{<}%
+  \defglyph\guilsinglright{>}%
+  \defglyph\leq{<=}%
+  \defglyph\lbracechar{\{}%
+  \defglyph\minus{-}%
+  \defglyph\point{.}%
+  \defglyph\pounds{pounds}%
+  \defglyph\print{-|}%
+  \defglyph\quotedblbase{"}%
+  \defglyph\quotedblleft{"}%
+  \defglyph\quotedblright{"}%
+  \defglyph\quoteleft{`}%
+  \defglyph\quoteright{'}%
+  \defglyph\quotesinglbase{,}%
+  \defglyph\rbracechar{\}}%
+  \defglyph\registeredsymbol{R}%
+  \defglyph\result{=>}%
+  \defglyph\textdegree{o}%
+  %
+  % We need to get rid of all macros, leaving only the arguments (if present).
+  % Of course this is not nearly correct, but it is the best we can do for now.
+  % makeinfo does not expand macros in the argument to @deffn, which ends up
+  % writing an index entry, and texindex isn't prepared for an index sort entry
+  % that starts with \.
+  %
+  % Since macro invocations are followed by braces, we can just redefine them
+  % to take a single TeX argument.  The case of a macro invocation that
+  % goes to end-of-line is not handled.
+  %
+  \macrolist
+  \let\value\indexnofontsvalue
+}
+\def\defglyph#1#2{\def#1##1{#2}} % see above
+
+
+
+
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{%
+  \iflinks
+  {%
+    %
+    \requireopenindexfile{#1}%
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \def\indextext{#2}%
+    \safewhatsit\doindwrite
+  }%
+  \fi
+}
+
+% Check if an index file has been opened, and if not, open it.
+\def\requireopenindexfile#1{%
+\ifnum\csname #1indfile\endcsname=0
+  \expandafter\newwrite \csname#1indfile\endcsname
+  \edef\suffix{#1}%
+  % A .fls suffix would conflict with the file extension for the output
+  % of -recorder, so use .f1s instead.
+  \ifx\suffix\indexisfl\def\suffix{f1}\fi
+  % Open the file
+  \immediate\openout\csname#1indfile\endcsname \jobname.\suffix
+  % Using \immediate above here prevents an object entering into the current
+  % box, which could confound checks such as those in \safewhatsit for
+  % preceding skips.
+  \typeout{Writing index file \jobname.\suffix}%
+\fi}
+\def\indexisfl{fl}
+
+% Definition for writing index entry sort key.
+{
+\catcode`\-=13
+\gdef\indexwritesortas{%
+  \begingroup
+  \indexnonalnumreappear
+  \indexwritesortasxxx}
+\gdef\indexwritesortasxxx#1{%
+  \xdef\indexsortkey{#1}\endgroup}
+}
+
+\def\indexwriteseealso#1{
+  \gdef\pagenumbertext{\string\seealso{#1}}%
+}
+\def\indexwriteseeentry#1{
+  \gdef\pagenumbertext{\string\seeentry{#1}}%
+}
+
+% The default definitions
+\def\sortas#1{}%
+\def\seealso#1{\i{\putwordSeeAlso}\ #1}% for sorted index file only
+\def\putwordSeeAlso{See also}
+\def\seeentry#1{\i{\putwordSee}\ #1}% for sorted index file only
+
+
+% Given index entry text like "aaa @subentry bbb @sortas{ZZZ}":
+%   * Set \bracedtext to "{aaa}{bbb}"
+%   * Set \fullindexsortkey to "aaa @subentry ZZZ"
+%   * If @seealso occurs, set \pagenumbertext
+%
+\def\splitindexentry#1{%
+  \gdef\fullindexsortkey{}%
+  \xdef\bracedtext{}%
+  \def\sep{}%
+  \def\seealso##1{}%
+  \def\seeentry##1{}%
+  \expandafter\doindexsegment#1\subentry\finish\subentry
+}
+
+% append the results from the next segment
+\def\doindexsegment#1\subentry{%
+  \def\segment{#1}%
+  \ifx\segment\isfinish
+  \else
+    %
+    % Fully expand the segment, throwing away any @sortas directives, and
+    % trim spaces.
+    \edef\trimmed{\segment}%
+    \edef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+    %
+    \xdef\bracedtext{\bracedtext{\trimmed}}%
+    %
+    % Get the string to sort by.  Process the segment with all
+    % font commands turned off.
+    \bgroup
+      \let\sortas\indexwritesortas
+      \let\seealso\indexwriteseealso
+      \let\seeentry\indexwriteseeentry
+      \indexnofonts
+      % The braces around the commands are recognized by texindex.
+      \def\lbracechar{{\string\indexlbrace}}%
+      \def\rbracechar{{\string\indexrbrace}}%
+      \let\{=\lbracechar
+      \let\}=\rbracechar
+      \def\@{{\string\indexatchar}}%
+      \def\atchar##1{\@}%
+      \def\backslashchar{{\string\indexbackslash}}%
+      \uccode`\~=`\\ \uppercase{\let~\backslashchar}%
+      %
+      \let\indexsortkey\empty
+      \global\let\pagenumbertext\empty
+      % Execute the segment and throw away the typeset output.  This executes
+      % any @sortas or @seealso commands in this segment.
+      \setbox\dummybox = \hbox{\segment}%
+      \ifx\indexsortkey\empty{%
+        \indexnonalnumdisappear
+        \xdef\trimmed{\segment}%
+        \xdef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+        \xdef\indexsortkey{\trimmed}%
+        \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi
+      }\fi
+      %
+      % Append to \fullindexsortkey.
+      \edef\tmp{\gdef\noexpand\fullindexsortkey{%
+                  \fullindexsortkey\sep\indexsortkey}}%
+      \tmp
+    \egroup
+    \def\sep{\subentry}%
+    %
+    \expandafter\doindexsegment
+  \fi
+}
+\def\isfinish{\finish}%
+\newbox\dummybox % used above
+
+\let\subentry\relax
+
+% Use \ instead of @ in index files.  To support old texi2dvi and texindex.
+% This works without changing the escape character used in the toc or aux
+% files because the index entries are fully expanded here, and \string uses
+% the current value of \escapechar.
+\def\escapeisbackslash{\escapechar=`\\}
+
+% Use \ in index files by default.  texi2dvi didn't support @ as the escape
+% character (as it checked for "\entry" in the files, and not "@entry").  When
+% the new version of texi2dvi has had a chance to become more prevalent, then
+% the escape character can change back to @ again.  This should be an easy
+% change to make now because both @ and \ are only used as escape characters in
+% index files, never standing for themselves.
+%
+\set txiindexescapeisbackslash
+
+% Write the entry in \indextext to the index file.
+%
+\def\doindwrite{%
+  \maybemarginindex
+  %
+  \atdummies
+  %
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax\else
+    \escapeisbackslash
+  \fi
+  %
+  % For texindex which always views { and } as separators.
+  \def\{{\lbracechar{}}%
+  \def\}{\rbracechar{}}%
+  \uccode`\~=`\\ \uppercase{\def~{\backslashchar{}}}%
+  %
+  % Split the entry into primary entry and any subentries, and get the index
+  % sort key.
+  \splitindexentry\indextext
+  %
+  % Set up the complete index entry, with both the sort key and
+  % the original text, including any font commands.  We write
+  % three arguments to \entry to the .?? file (four in the
+  % subentry case), texindex reduces to two when writing the .??s
+  % sorted result.
+  %
+  \edef\temp{%
+    \write\writeto{%
+      \string\entry{\fullindexsortkey}%
+        {\ifx\pagenumbertext\empty\noexpand\folio\else\pagenumbertext\fi}%
+        \bracedtext}%
+  }%
+  \temp
+}
+
+% Put the index entry in the margin if desired (undocumented).
+\def\maybemarginindex{%
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \relax\indextext}}%
+  \fi
+}
+\let\SETmarginindex=\relax
+
+
+% Take care of unwanted page breaks/skips around a whatsit:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again.  Otherwise, the whatsit generated by the
+% \write or \pdfdest will make \lastskip zero.  The result is that
+% sequences like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode.  We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip.  \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip.  The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+\newskip\whatsitskip
+\newcount\whatsitpenalty
+%
+% ..., ready, GO:
+%
+\def\safewhatsit#1{\ifhmode
+  #1%
+ \else
+  % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+  \whatsitskip = \lastskip
+  \edef\lastskipmacro{\the\lastskip}%
+  \whatsitpenalty = \lastpenalty
+  %
+  % If \lastskip is nonzero, that means the last item was a
+  % skip.  And since a skip is discardable, that means this
+  % -\whatsitskip glue we're inserting is preceded by a
+  % non-discardable item, therefore it is not a potential
+  % breakpoint, therefore no \nobreak needed.
+  \ifx\lastskipmacro\zeroskipmacro
+  \else
+    \vskip-\whatsitskip
+  \fi
+  %
+  #1%
+  %
+  \ifx\lastskipmacro\zeroskipmacro
+    % If \lastskip was zero, perhaps the last item was a penalty, and
+    % perhaps it was >=10000, e.g., a \nobreak.  In that case, we want
+    % to re-insert the same penalty (values >10000 are used for various
+    % signals); since we just inserted a non-discardable item, any
+    % following glue (such as a \parskip) would be a breakpoint.  For example:
+    %   @deffn deffn-whatever
+    %   @vindex index-whatever
+    %   Description.
+    % would allow a break between the index-whatever whatsit
+    % and the "Description." paragraph.
+    \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi
+  \else
+    % On the other hand, if we had a nonzero \lastskip,
+    % this make-up glue would be preceded by a non-discardable item
+    % (the whatsit from the \write), so we must insert a \nobreak.
+    \nobreak\vskip\whatsitskip
+  \fi
+\fi}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%  \entry {topic}{}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+%  \secondary {subtopic}{}
+%     for a subtopic with sub-subtopics
+%  \tertiary {subtopic}{subsubtopic}{pagelist}
+%     for each sub-subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \smallfonts \rm
+  \tolerance = 9500
+  \plainfrenchspacing
+  \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+  %
+  % See comment in \requireopenindexfile.
+  \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
+  %
+  % See if the index file exists and is nonempty.
+  \openin 1 \jobname.\indexname s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    \putwordIndexNonexistent
+    \typeout{No file \jobname.\indexname s.}%
+  \else
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \thisline
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      \expandafter\printindexzz\thisline\relax\relax\finish%
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% If the index file starts with a backslash, forgo reading the index
+% file altogether.  If somebody upgrades texinfo.tex they may still have
+% old index files using \ as the escape character.  Reading this would
+% at best lead to typesetting garbage, at worst a TeX syntax error.
+\def\printindexzz#1#2\finish{%
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax
+    \uccode`\~=`\\ \uppercase{\if\noexpand~}\noexpand#1
+      \expandafter\ifx\csname SETtxiskipindexfileswithbackslash\endcsname\relax
+\errmessage{%
+ERROR: A sorted index file in an obsolete format was skipped.
+To fix this problem, please upgrade your version of 'texi2dvi'
+or 'texi2pdf' to that at <https://ftp.gnu.org/gnu/texinfo>.
+If you are using an old version of 'texindex' (part of the Texinfo
+distribution), you may also need to upgrade to a newer version (at least 6.0).
+You may be able to typeset the index if you run
+'texindex \jobname.\indexname' yourself.
+You could also try setting the 'txiindexescapeisbackslash' flag by
+running a command like
+'texi2dvi -t "@set txiindexescapeisbackslash" \jobname.texi'.  If you do
+this, Texinfo will try to use index files in the old format.
+If you continue to have problems, deleting the index files and starting again
+might help (with 'rm \jobname.?? \jobname.??s')%
+}%
+      \else
+        (Skipped sorted index file in obsolete format)
+      \fi
+    \else
+      \begindoublecolumns
+      \input \jobname.\indexname s
+      \enddoublecolumns
+    \fi
+  \else
+    \begindoublecolumns
+    \catcode`\\=0\relax
+    \catcode`\@=12\relax
+    \input \jobname.\indexname s
+    \enddoublecolumns
+  \fi
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+{\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13
+\catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13
+\catcode`\$=3
+\gdef\initialglyphs{%
+  % special control sequences used in the index sort key
+  \let\indexlbrace\{%
+  \let\indexrbrace\}%
+  \let\indexatchar\@%
+  \def\indexbackslash{\math{\backslash}}%
+  %
+  % Some changes for non-alphabetic characters.  Using the glyphs from the
+  % math fonts looks more consistent than the typewriter font used elsewhere
+  % for these characters.
+  \uccode`\~=`\\ \uppercase{\def~{\math{\backslash}}}
+  %
+  % In case @\ is used for backslash
+  \uppercase{\let\\=~}
+  % Can't get bold backslash so don't use bold forward slash
+  \catcode`\/=13
+  \def/{{\secrmnotbold \normalslash}}%
+  \def-{{\normaldash\normaldash}}% en dash `--'
+  \def^{{\chapbf \normalcaret}}%
+  \def~{{\chapbf \normaltilde}}%
+  \def\_{%
+     \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }%
+  \def|{$\vert$}%
+  \def<{$\less$}%
+  \def>{$\gtr$}%
+  \def+{$\normalplus$}%
+}}
+
+\def\initial{%
+  \bgroup
+  \initialglyphs
+  \initialx
+}
+
+\def\initialx#1{%
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  % The glue before the bonus allows a little bit of space at the
+  % bottom of a column to reduce an increase in inter-line spacing.
+  \nobreak
+  \vskip 0pt plus 5\baselineskip
+  \penalty -300
+  \vskip 0pt plus -5\baselineskip
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  %
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus 1\baselineskip
+  \leftline{\secfonts \kern-0.05em \secbf #1}%
+  % \secfonts is inside the argument of \leftline so that the change of
+  % \baselineskip will not affect any glue inserted before the vbox that
+  % \leftline creates.
+  % Do our best not to break after the initial.
+  \nobreak
+  \vskip .33\baselineskip plus .1\baselineskip
+  \egroup % \initialglyphs
+}
+
+\newdimen\entryrightmargin
+\entryrightmargin=0pt
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin.  It is used for index
+% and table of contents entries.  The paragraph is indented by \leftskip.
+%
+\def\entry{%
+  \begingroup
+    %
+    % Start a new paragraph if necessary, so our assignments below can't
+    % affect previous text.
+    \par
+    %
+    % No extra space above this paragraph.
+    \parskip = 0in
+    %
+    % When reading the text of entry, convert explicit line breaks
+    % from @* into spaces.  The user might give these in long section
+    % titles, for instance.
+    \def\*{\unskip\space\ignorespaces}%
+    \def\entrybreak{\hfil\break}% An undocumented command
+    %
+    % Swallow the left brace of the text (first parameter):
+    \afterassignment\doentry
+    \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\def\doentry{%
+    % Save the text of the entry
+    \global\setbox\boxA=\hbox\bgroup
+    \bgroup % Instead of the swallowed brace.
+      \noindent
+      \aftergroup\finishentry
+      % And now comes the text of the entry.
+      % Not absorbing as a macro argument reduces the chance of problems
+      % with catcodes occurring.
+}
+{\catcode`\@=11
+\gdef\finishentry#1{%
+    \egroup % end box A
+    \dimen@ = \wd\boxA % Length of text of entry
+    \global\setbox\boxA=\hbox\bgroup
+      \unhbox\boxA
+      % #1 is the page number.
+      %
+      % Get the width of the page numbers, and only use
+      % leaders if they are present.
+      \global\setbox\boxB = \hbox{#1}%
+      \ifdim\wd\boxB = 0pt
+        \null\nobreak\hfill\ %
+      \else
+        %
+        \null\nobreak\indexdotfill % Have leaders before the page number.
+        %
+        \ifpdforxetex
+          \pdfgettoks#1.%
+          \hskip\skip\thinshrinkable\the\toksA
+        \else
+          \hskip\skip\thinshrinkable #1%
+        \fi
+      \fi
+    \egroup % end \boxA
+    \ifdim\wd\boxB = 0pt
+      \noindent\unhbox\boxA\par
+      \nobreak
+    \else\bgroup
+      % We want the text of the entries to be aligned to the left, and the
+      % page numbers to be aligned to the right.
+      %
+      \parindent = 0pt
+      \advance\leftskip by 0pt plus 1fil
+      \advance\leftskip by 0pt plus -1fill
+      \rightskip = 0pt plus -1fil
+      \advance\rightskip by 0pt plus 1fill
+      % Cause last line, which could consist of page numbers on their own
+      % if the list of page numbers is long, to be aligned to the right.
+      \parfillskip=0pt plus -1fill
+      %
+      \advance\rightskip by \entryrightmargin
+      % Determine how far we can stretch into the margin.
+      % This allows, e.g., "Appendix H  GNU Free Documentation License" to
+      % fit on one line in @letterpaper format.
+      \ifdim\entryrightmargin>2.1em
+        \dimen@i=2.1em
+      \else
+        \dimen@i=0em
+      \fi
+      \advance \parfillskip by 0pt minus 1\dimen@i
+      %
+      \dimen@ii = \hsize
+      \advance\dimen@ii by -1\leftskip
+      \advance\dimen@ii by -1\entryrightmargin
+      \advance\dimen@ii by 1\dimen@i
+      \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line
+      \ifdim\dimen@ > 0.8\dimen@ii   % due to long index text
+        % Try to split the text roughly evenly.  \dimen@ will be the length of
+        % the first line.
+        \dimen@ = 0.7\dimen@
+        \dimen@ii = \hsize
+        \ifnum\dimen@>\dimen@ii
+          % If the entry is too long (for example, if it needs more than
+          % two lines), use all the space in the first line.
+          \dimen@ = \dimen@ii
+        \fi
+        \advance\leftskip by 0pt plus 1fill % ragged right
+        \advance \dimen@ by 1\rightskip
+        \parshape = 2 0pt \dimen@ 0em \dimen@ii
+        % Ideally we'd add a finite glue at the end of the first line only,
+        % instead of using \parshape with explicit line lengths, but TeX
+        % doesn't seem to provide a way to do such a thing.
+        %
+        % Indent all lines but the first one.
+        \advance\leftskip by 1em
+        \advance\parindent by -1em
+      \fi\fi
+      \indent % start paragraph
+      \unhbox\boxA
+      %
+      % Do not prefer a separate line ending with a hyphen to fewer lines.
+      \finalhyphendemerits = 0
+      %
+      % Word spacing - no stretch
+      \spaceskip=\fontdimen2\font minus \fontdimen4\font
+      %
+      \linepenalty=1000  % Discourage line breaks.
+      \hyphenpenalty=5000  % Discourage hyphenation.
+      %
+      \par % format the paragraph
+    \egroup % The \vbox
+    \fi
+  \endgroup
+}}
+
+\newskip\thinshrinkable
+\skip\thinshrinkable=.15em minus .15em
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+% The filll stretch here overpowers both the fil and fill stretch to push
+% the page number to the right.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll}
+
+
+\def\primary #1{\line{#1\hfil}}
+
+\def\secondary{\indententry{0.5cm}}
+\def\tertiary{\indententry{1cm}}
+
+\def\indententry#1#2#3{%
+  \bgroup
+  \leftskip=#1
+  \entry{#2}{#3}%
+  \egroup
+}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11  % private names
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % If not much space left on page, start a new page.
+  \ifdim\pagetotal>0.8\vsize\vfill\eject\fi
+  %
+  % Grab any single-column material above us.
+  \output = {%
+    \savetopmark
+    %
+    \global\setbox\partialpage = \vbox{%
+      % Unvbox the main output page.
+      \unvbox\PAGE
+      \kern-\topskip \kern\baselineskip
+    }%
+  }%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \advance\vsize by -\ht\partialpage
+  \vsize = 2\vsize
+  %
+  % For the benefit of balancing columns
+  \advance\baselineskip by 0pt plus 0.5pt
+}
+
+% The double-column output routine for all double-column pages except
+% the last, which is done by \balancecolumns.
+%
+\def\doublecolumnout{%
+  %
+  \savetopmark
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@
+  \global\advance\vsize by 2\ht\partialpage
+  \onepageout\pagesofar % empty except for the first time we are called
+  \unvbox\PAGE
+  \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\txipagewidth{\box0\hfil\box2}%
+}
+
+
+% Finished with double columns.
+\def\enddoublecolumns{%
+  % The following penalty ensures that the page builder is exercised
+  % _before_ we change the output routine.  This is necessary in the
+  % following situation:
+  %
+  % The last section of the index consists only of a single entry.
+  % Before this section, \pagetotal is less than \pagegoal, so no
+  % break occurs before the last section starts.  However, the last
+  % section, consisting of \initial and the single \entry, does not
+  % fit on the page and has to be broken off.  Without the following
+  % penalty the page builder will not be exercised until \eject
+  % below, and by that time we'll already have changed the output
+  % routine to the \balancecolumns version, so the next-to-last
+  % double-column page will be processed with \balancecolumns, which
+  % is wrong:  The two columns will go to the main vertical list, with
+  % the broken-off section in the recent contributions.  As soon as
+  % the output routine finishes, TeX starts reconsidering the page
+  % break.  The two columns and the broken-off section both fit on the
+  % page, because the two columns now take up only half of the page
+  % goal.  When TeX sees \eject from below which follows the final
+  % section, it invokes the new output routine that we've set after
+  % \balancecolumns below; \onepageout will try to fit the two columns
+  % and the final section into the vbox of \txipageheight (see
+  % \pagebody), causing an overfull box.
+  %
+  % Note that glue won't work here, because glue does not exercise the
+  % page builder, unlike penalties (see The TeXbook, pp. 280-281).
+  \penalty0
+  %
+  \output = {%
+    % Split the last of the double-column material.
+    \savetopmark
+    \balancecolumns
+  }%
+  \eject % call the \output just set
+  \ifdim\pagetotal=0pt
+    % Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.
+    \global\output=\expandafter{\the\defaultoutput}
+    %
+    \endgroup % started in \begindoublecolumns
+    % Leave the double-column material on the current page, no automatic
+    % page break.
+    \box\balancedcolumns
+    %
+    % \pagegoal was set to the doubled \vsize above, since we restarted
+    % the current page.  We're now back to normal single-column
+    % typesetting, so reset \pagegoal to the normal \vsize.
+    \global\vsize = \txipageheight %
+    \pagegoal = \txipageheight %
+  \else
+    % We had some left-over material.  This might happen when \doublecolumnout
+    % is called in \balancecolumns.  Try again.
+    \expandafter\enddoublecolumns
+  \fi
+}
+\newbox\balancedcolumns
+\setbox\balancedcolumns=\vbox{shouldnt see this}%
+%
+% Only called for the last of the double column material.  \doublecolumnout
+% does the others.
+\def\balancecolumns{%
+  \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \ifdim\dimen@<7\baselineskip
+    % Don't split a short final column in two.
+    \setbox2=\vbox{}%
+    \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+  \else
+    % double the leading vertical space
+    \advance\dimen@ by \topskip
+    \advance\dimen@ by-\baselineskip
+    \divide\dimen@ by 2 % target to split to
+    \dimen@ii = \dimen@
+    \splittopskip = \topskip
+    % Loop until left column is at least as high as the right column.
+    {%
+      \vbadness = 10000
+      \loop
+        \global\setbox3 = \copy0
+        \global\setbox1 = \vsplit3 to \dimen@
+      \ifdim\ht1<\ht3
+        \global\advance\dimen@ by 1pt
+      \repeat
+    }%
+    % Now the left column is in box 1, and the right column in box 3.
+    %
+    % Check whether the left column has come out higher than the page itself.
+    % (Note that we have doubled \vsize for the double columns, so
+    % the actual height of the page is 0.5\vsize).
+    \ifdim2\ht1>\vsize
+      % It appears that we have been called upon to balance too much material.
+      % Output some of it with \doublecolumnout, leaving the rest on the page.
+      \setbox\PAGE=\box0
+      \doublecolumnout
+    \else
+      % Compare the heights of the two columns.
+      \ifdim4\ht1>5\ht3
+        % Column heights are too different, so don't make their bottoms
+        % flush with each other.
+        \setbox2=\vbox to \ht1 {\unvbox3\vfill}%
+        \setbox0=\vbox to \ht1 {\unvbox1\vfill}%
+      \else
+        % Make column bottoms flush with each other.
+        \setbox2=\vbox to\ht1{\unvbox3\unskip}%
+        \setbox0=\vbox to\ht1{\unvbox1\unskip}%
+      \fi
+      \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+    \fi
+  \fi
+  %
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+  \chapoddpage
+  \null
+  \vskip.3\vsize  % move it down on the page a bit
+  \begingroup
+    \noindent \titlefonts\rm #1\par % the text
+    \let\lastnode=\empty      % no node to associate with
+    \writetocentry{part}{#1}{}% but put it in the toc
+    \headingsoff              % no headline or footline on the part page
+    % This outputs a mark at the end of the page that clears \thischapter
+    % and \thissection, as is done in \startcontents.
+    \let\pchapsepmacro\relax
+    \chapmacro{}{Yomitfromtoc}{}%
+    \chapoddpage
+  \endgroup
+}
+
+% \unnumberedno is an oxymoron.  But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number".  We avoid collisions with chapter
+% numbers by starting them at 10000.  (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+  \ifnum\appendixno=`A A%
+  \else\ifnum\appendixno=`B B%
+  \else\ifnum\appendixno=`C C%
+  \else\ifnum\appendixno=`D D%
+  \else\ifnum\appendixno=`E E%
+  \else\ifnum\appendixno=`F F%
+  \else\ifnum\appendixno=`G G%
+  \else\ifnum\appendixno=`H H%
+  \else\ifnum\appendixno=`I I%
+  \else\ifnum\appendixno=`J J%
+  \else\ifnum\appendixno=`K K%
+  \else\ifnum\appendixno=`L L%
+  \else\ifnum\appendixno=`M M%
+  \else\ifnum\appendixno=`N N%
+  \else\ifnum\appendixno=`O O%
+  \else\ifnum\appendixno=`P P%
+  \else\ifnum\appendixno=`Q Q%
+  \else\ifnum\appendixno=`R R%
+  \else\ifnum\appendixno=`S S%
+  \else\ifnum\appendixno=`T T%
+  \else\ifnum\appendixno=`U U%
+  \else\ifnum\appendixno=`V V%
+  \else\ifnum\appendixno=`W W%
+  \else\ifnum\appendixno=`X X%
+  \else\ifnum\appendixno=`Y Y%
+  \else\ifnum\appendixno=`Z Z%
+  % The \the is necessary, despite appearances, because \appendixletter is
+  % expanded while writing the .toc file.  \char\appendixno is not
+  % expandable, thus it is written literally, thus all appendixes come out
+  % with the same letter (or @) in the toc without it.
+  \else\char\the\appendixno
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter.  Page headings and footings can use
+% these.  @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+  % Compute the abs. sec. level:
+  \absseclevel=#2
+  \advance\absseclevel by \secbase
+  % Make sure \absseclevel doesn't fall outside the range:
+  \ifnum \absseclevel < 0
+    \absseclevel = 0
+  \else
+    \ifnum \absseclevel > 3
+      \absseclevel = 3
+    \fi
+  \fi
+  % The heading type:
+  \def\headtype{#1}%
+  \if \headtype U%
+    \ifnum \absseclevel < \unnlevel
+      \chardef\unnlevel = \absseclevel
+    \fi
+  \else
+    % Check for appendix sections:
+    \ifnum \absseclevel = 0
+      \edef\chapheadtype{\headtype}%
+    \else
+      \if \headtype A\if \chapheadtype N%
+       \errmessage{@appendix... within a non-appendix chapter}%
+      \fi\fi
+    \fi
+    % Check for numbered within unnumbered:
+    \ifnum \absseclevel > \unnlevel
+      \def\headtype{U}%
+    \else
+      \chardef\unnlevel = 3
+    \fi
+  \fi
+  % Now print the heading:
+  \if \headtype U%
+    \ifcase\absseclevel
+       \unnumberedzzz{#3}%
+    \or \unnumberedseczzz{#3}%
+    \or \unnumberedsubseczzz{#3}%
+    \or \unnumberedsubsubseczzz{#3}%
+    \fi
+  \else
+    \if \headtype A%
+      \ifcase\absseclevel
+         \appendixzzz{#3}%
+      \or \appendixsectionzzz{#3}%
+      \or \appendixsubseczzz{#3}%
+      \or \appendixsubsubseczzz{#3}%
+      \fi
+    \else
+      \ifcase\absseclevel
+         \chapterzzz{#3}%
+      \or \seczzz{#3}%
+      \or \numberedsubseczzz{#3}%
+      \or \numberedsubsubseczzz{#3}%
+      \fi
+    \fi
+  \fi
+  \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered.  Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v.  By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+  % section resetting is \global in case the chapter is in a group, such
+  % as an @include file.
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\chapno by 1
+  %
+  % Used for \float.
+  \gdef\chaplevelprefix{\the\chapno.}%
+  \resetallfloatnos
+  %
+  % \putwordChapter can contain complex things in translations.
+  \toks0=\expandafter{\putwordChapter}%
+  \message{\the\toks0 \space \the\chapno}%
+  %
+  % Write the actual heading.
+  \chapmacro{#1}{Ynumbered}{\the\chapno}%
+  %
+  % So @section and the like are numbered underneath this chapter.
+  \global\let\section = \numberedsec
+  \global\let\subsection = \numberedsubsec
+  \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\appendixno by 1
+  \gdef\chaplevelprefix{\appendixletter.}%
+  \resetallfloatnos
+  %
+  % \putwordAppendix can contain complex things in translations.
+  \toks0=\expandafter{\putwordAppendix}%
+  \message{\the\toks0 \space \appendixletter}%
+  %
+  \chapmacro{#1}{Yappendix}{\appendixletter}%
+  %
+  \global\let\section = \appendixsec
+  \global\let\subsection = \appendixsubsec
+  \global\let\subsubsection = \appendixsubsubsec
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\def\unnumberedzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\unnumberedno by 1
+  %
+  % Since an unnumbered has no number, no prefix for figures.
+  \global\let\chaplevelprefix = \empty
+  \resetallfloatnos
+  %
+  % This used to be simply \message{#1}, but TeX fully expands the
+  % argument to \message.  Therefore, if #1 contained @-commands, TeX
+  % expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+  % expanded @cite (which turns out to cause errors because \cite is meant
+  % to be executed, not expanded).
+  %
+  % Anyway, we don't want the fully-expanded definition of @cite to appear
+  % as a result of the \message, we just want `@cite' itself.  We use
+  % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+  % simply yielding the contents of <toks register>.  (We also do this for
+  % the toc entries.)
+  \toks0 = {#1}%
+  \message{(\the\toks0)}%
+  %
+  \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+  %
+  \global\let\section = \unnumberedsec
+  \global\let\subsection = \unnumberedsubsec
+  \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+  \let\centerparametersmaybe = \centerparameters
+  \unnmhead0{#1}%
+  \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+%
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+%
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+%
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynumbered}%
+                 {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\def\unnumberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{%
+  {\advance\chapheadingskip by 10pt \chapbreak }%
+  \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+  \vbox{\chapfonts \raggedtitlesettings #1\par}%
+  \nobreak\bigskip \nobreak
+  \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+
+% Start a new page
+\def\chappager{\par\vfill\supereject}
+
+% \chapoddpage - start on an odd page for a new chapter
+% Because \domark is called before \chapoddpage, the filler page will
+% get the headings for the next chapter, which is wrong.  But we don't
+% care -- we just disable all headings on the filler page.
+\def\chapoddpage{%
+  \chappager
+  \ifodd\pageno \else
+    \begingroup
+      \headingsoff
+      \null
+      \chappager
+    \endgroup
+  \fi
+}
+
+\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% \chapmacro - Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+% Not used for @heading series.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yappendixkeyword{Yappendix}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+%
+\def\chapmacro#1#2#3{%
+  \expandafter\ifx\thisenv\titlepage\else
+    \checkenv{}% chapters, etc., should not start inside an environment.
+  \fi
+  % Insert the first mark before the heading break (see notes for \domark).
+  \let\prevchapterdefs=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \gdef\currentsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+                        \gdef\thissection{}}%
+  %
+  \def\temptype{#2}%
+  \ifx\temptype\Ynothingkeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{\thischaptername}}%
+  \else\ifx\temptype\Yomitfromtockeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{}}%
+  \else\ifx\temptype\Yappendixkeyword
+    \toks0={#1}%
+    \xdef\currentchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\appendixletter}%
+      % \noexpand\putwordAppendix avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordAppendix{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \else
+    \toks0={#1}%
+    \xdef\currentchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\the\chapno}%
+      % \noexpand\putwordChapter avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordChapter{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \fi\fi\fi
+  %
+  % Output the mark.  Pass it through \safewhatsit, to take care of
+  % the preceding space.
+  \safewhatsit\domark
+  %
+  % Insert the chapter heading break.
+  \pchapsepmacro
+  %
+  % Now the second mark, after the heading break.  No break points
+  % between here and the heading.
+  \let\prevchapterdefs=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \domark
+  %
+  {%
+    \chapfonts \rm
+    \let\footnote=\errfootnoteheading % give better error message
+    %
+    % Have to define \currentsection before calling \donoderef, because the
+    % xref code eventually uses it.  On the other hand, it has to be called
+    % after \pchapsepmacro, or the headline will change too soon.
+    \gdef\currentsection{#1}%
+    %
+    % Only insert the separating space if we have a chapter/appendix
+    % number, and don't print the unnumbered ``number''.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unnchap}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+      \def\toctype{omit}%
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+      \def\toctype{app}%
+    \else
+      \setbox0 = \hbox{#3\enspace}%
+      \def\toctype{numchap}%
+    \fi\fi\fi
+    %
+    % Write the toc entry for this chapter.  Must come before the
+    % \donoderef, because we include the current node name in the toc
+    % entry, and \donoderef resets it to empty.
+    \writetocentry{\toctype}{#1}{#3}%
+    %
+    % For pdftex, we have to write out the node definition (aka, make
+    % the pdfdest) after any page break, but before the actual text has
+    % been typeset.  If the destination for the pdf outline is after the
+    % text, then jumping from the outline may wind up with the text not
+    % being visible, for instance under high magnification.
+    \donoderef{#2}%
+    %
+    % Typeset the actual heading.
+    \nobreak % Avoid page breaks at the interline glue.
+    \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+  \advance\rightskip by 3\rightskip
+  \leftskip = \rightskip
+  \parfillskip = 0pt
+}
+
+
+% Section titles.  These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text of the title,
+% #2 is the section level (sec/subsec/subsubsec),
+% #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc),
+% #4 is the section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+  {%
+    \def\sectionlevel{#2}%
+    \def\temptype{#3}%
+    %
+    % It is ok for the @heading series commands to appear inside an
+    % environment (it's been historically allowed, though the logic is
+    % dubious), but not the others.
+    \ifx\temptype\Yomitfromtockeyword\else
+      \checkenv{}% non-@*heading should not be in an environment.
+    \fi
+    \let\footnote=\errfootnoteheading
+    %
+    % Switch to the right set of fonts.
+    \csname #2fonts\endcsname \rm
+    %
+    % Insert first mark before the heading break (see notes for \domark).
+    \let\prevsectiondefs=\currentsectiondefs
+    \ifx\temptype\Ynothingkeyword
+      \ifx\sectionlevel\seckeyword
+        
\gdef\currentsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}%
+                              \gdef\thissection{\thissectionname}}%
+      \fi
+    \else\ifx\temptype\Yomitfromtockeyword
+      % Don't redefine \thissection.
+    \else\ifx\temptype\Yappendixkeyword
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\currentsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \else
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\currentsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \fi\fi\fi
+    %
+    % Go into vertical mode.  Usually we'll already be there, but we
+    % don't want the following whatsit to end up in a preceding paragraph
+    % if the document didn't happen to have a blank line.
+    \par
+    %
+    % Output the mark.  Pass it through \safewhatsit, to take care of
+    % the preceding space.
+    \safewhatsit\domark
+    %
+    % Insert space above the heading.
+    \csname #2headingbreak\endcsname
+    %
+    % Now the second mark, after the heading break.  No break points
+    % between here and the heading.
+    \global\let\prevsectiondefs=\currentsectiondefs
+    \domark
+    %
+    % Only insert the space after the number if we have a section number.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unn}%
+      \gdef\currentsection{#1}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      % for @headings -- no section number, don't include in toc,
+      % and don't redefine \currentsection.
+      \setbox0 = \hbox{}%
+      \def\toctype{omit}%
+      \let\sectionlevel=\empty
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{app}%
+      \gdef\currentsection{#1}%
+    \else
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{num}%
+      \gdef\currentsection{#1}%
+    \fi\fi\fi
+    %
+    % Write the toc entry (before \donoderef).  See comments in \chapmacro.
+    \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+    %
+    % Write the node reference (= pdf destination for pdftex).
+    % Again, see comments in \chapmacro.
+    \donoderef{#3}%
+    %
+    % Interline glue will be inserted when the vbox is completed.
+    % That glue will be a valid breakpoint for the page, since it'll be
+    % preceded by a whatsit (usually from the \donoderef, or from the
+    % \writetocentry if there was no node).  We don't want to allow that
+    % break, since then the whatsits could end up on page n while the
+    % section is on page n+1, thus toc/etc. are wrong.  Debian bug 276000.
+    \nobreak
+    %
+    % Output the actual section heading.
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+          \hangindent=\wd0  % zero if no section number
+          \unhbox0 #1}%
+  }%
+  % Add extra space after the heading -- half of whatever came above it.
+  % Don't allow stretch, though.
+  \kern .5 \csname #2headingskip\endcsname
+  %
+  % Do not let the kern be a potential breakpoint, as it would be if it
+  % was followed by glue.
+  \nobreak
+  %
+  % We'll almost certainly start a paragraph next, so don't let that
+  % glue accumulate.  (Not a breakpoint because it's preceded by a
+  % discardable item.)  However, when a paragraph is not started next
+  % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+  % or the negative glue will cause weirdly wrong output, typically
+  % obscuring the section heading with something else.
+  \vskip-\parskip
+  %
+  % This is so the last item on the main vertical list is a known
+  % \penalty > 10000, so \startdefun, etc., can recognize the situation
+  % and do the needful.
+  \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this.  The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything.  This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+  \edef\writetoctype{#1}%
+  \ifx\writetoctype\omitkeyword \else
+    \iftocfileopened\else
+      \immediate\openout\tocfile = \jobname.toc
+      \global\tocfileopenedtrue
+    \fi
+    %
+    \iflinks
+      {\atdummies
+       \edef\temp{%
+         \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+       \temp
+      }%
+    \fi
+  \fi
+  %
+  % Tell \shipout to create a pdf destination on each page, if we're
+  % writing pdf.  These are used in the table of contents.  We can't
+  % just write one on every page because the title pages are numbered
+  % 1 and 2 (the page numbers aren't printed), and so are the first
+  % two pages of the document.  Thus, we'd have two destinations named
+  % `1', and two named `2'.
+  \ifpdforxetex
+    \global\pdfmakepagedesttrue
+  \fi
+}
+
+
+% These characters do not print properly in the Computer Modern roman
+% fonts, so we must take special care.  This is more or less redundant
+% with the Texinfo input format setup at the end of this file.
+%
+\def\activecatcodes{%
+  \catcode`\"=\active
+  \catcode`\$=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
+  \catcode`\\=\active
+  \catcode`\^=\active
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\~=\active
+}
+
+
+% Read the toc file, which is essentially Texinfo input.
+\def\readtocfile{%
+  \setupdatafile
+  \activecatcodes
+  \input \tocreadfilename
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+  % If @setchapternewpage on, and @headings double, the contents should
+  % start on an odd page, unlike chapters.  Thus, we maintain
+  % \contentsalignmacro in parallel with \pagealignmacro.
+  % From: Torbjorn Granlund <tege@matematik.su.se>
+  \contentsalignmacro
+  \immediate\closeout\tocfile
+  %
+  % Don't need to put `Contents' or `Short Contents' in the headline.
+  % It is abundantly clear what they are.
+  \chapmacro{#1}{Yomitfromtoc}{}%
+  %
+  \savepageno = \pageno
+  \begingroup                  % Set up to handle contents files properly.
+    \raggedbottom              % Worry more about breakpoints than the bottom.
+    \entryrightmargin=\contentsrightmargin % Don't use the full line length.
+    %
+    % Roman numerals for page numbers.
+    \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+}
+
+% redefined for the two-volume lispref.  We always output on
+% \jobname.toc even if this is redefined.
+%
+\def\tocreadfilename{\jobname.toc}
+
+% Normal (long) toc.
+%
+\def\contents{%
+  \startcontents{\putwordTOC}%
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+    \ifeof 1 \else
+      \pdfmakeoutlines
+    \fi
+    \closein 1
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+  \startcontents{\putwordShortTOC}%
+    %
+    \let\partentry = \shortpartentry
+    \let\numchapentry = \shortchapentry
+    \let\appentry = \shortchapentry
+    \let\unnchapentry = \shortunnchapentry
+    % We want a true roman here for the page numbers.
+    \secfonts
+    \let\rm=\shortcontrm \let\bf=\shortcontbf
+    \let\sl=\shortcontsl \let\tt=\shortconttt
+    \rm
+    \hyphenpenalty = 10000
+    \advance\baselineskip by 1pt % Open it up a little.
+    \def\numsecentry##1##2##3##4{}
+    \let\appsecentry = \numsecentry
+    \let\unnsecentry = \numsecentry
+    \let\numsubsecentry = \numsecentry
+    \let\appsubsecentry = \numsecentry
+    \let\unnsubsecentry = \numsecentry
+    \let\numsubsubsecentry = \numsecentry
+    \let\appsubsubsecentry = \numsecentry
+    \let\unnsubsubsecentry = \numsecentry
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \closein 1
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+  % This space should be enough, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % But use \hss just in case.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  %
+  % We'd like to right-justify chapter numbers, but that looks strange
+  % with appendix letters.  And right-justifying numbers and
+  % left-justifying letters looks strange when there is less than 10
+  % chapters.  Have to read the whole toc once to know how many chapters
+  % there are before deciding ...
+  \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Parts, in the main contents.  Replace the part number, which doesn't
+% exist, with an empty box.  Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{%
+  % Add stretch and a bonus for breaking the page before the part heading.
+  % This reduces the chance of the page being broken immediately after the
+  % part heading, before a following chapter heading.
+  \vskip 0pt plus 5\baselineskip
+  \penalty-300
+  \vskip 0pt plus -5\baselineskip
+  \dochapentry{\numeralbox\labelspace#1}{}%
+}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+  \penalty-300
+  \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+  \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+  % We use M since it's probably the widest letter.
+  \setbox0 = \hbox{\putwordAppendix{} M}%
+  \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     % Move the page numbers slightly to the right
+     \advance\entryrightmargin by -0.05em
+     \chapentryfonts
+     \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @tex ... @end tex    escapes into raw TeX temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain @ character.
+
+\envdef\tex{%
+  \setupmarkupstyle{tex}%
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+  \catcode `\%=14
+  \catcode `\+=\other
+  \catcode `\"=\other
+  \catcode `\|=\other
+  \catcode `\<=\other
+  \catcode `\>=\other
+  \catcode `\`=\other
+  \catcode `\'=\other
+  %
+  % ' is active in math mode (mathcode"8000).  So reset it, and all our
+  % other math active characters (just in case), to plain's definitions.
+  \mathactive
+  %
+  % Inverse of the list at the beginning of the file.
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\/=\ptexslash
+  \let\sp=\ptexsp
+  \let\*=\ptexstar
+  %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode
+  \let\t=\ptext
+  \expandafter \let\csname top\endcsname=\ptextop  % we've made it outer
+  \let\frenchspacing=\plainfrenchspacing
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      \ifnum\lastpenalty<10000
+        % Penalize breaking before the environment, because preceding text
+        % often leads into it.
+        \penalty100
+      \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+\def\afterenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      % it's not a good place to break if the last penalty was \nobreak
+      % or better ...
+      \ifnum\lastpenalty<10000 \penalty-50 \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins; it will
+% also clear it, so that its embedded environments do the narrowing again.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+% only require the font if @cartouche is actually used
+\def\cartouchefontdefs{%
+  \font\circle=lcircle10\relax
+  \circthick=\fontdimen8\circle
+}
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+
+
+\envdef\cartouche{%
+  \cartouchefontdefs
+  \ifhmode\par\fi  % can't be in the midst of a paragraph.
+  \startsavinginserts
+  \lskip=\leftskip \rskip=\rightskip
+  \leftskip=0pt\rightskip=0pt % we want these *outside*.
+  \cartinner=\hsize \advance\cartinner by-\lskip
+  \advance\cartinner by-\rskip
+  \cartouter=\hsize
+  \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+                               % side, and for 6pt waste from
+                               % each corner char, and rule thickness
+  \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+  %
+  % If this cartouche directly follows a sectioning command, we need the
+  % \parskip glue (backspaced over by default) or the cartouche can
+  % collide with the section heading.
+  \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+  %
+  \setbox\groupbox=\vbox\bgroup
+      \baselineskip=0pt\parskip=0pt\lineskip=0pt
+      \carttop
+      \hbox\bgroup
+         \hskip\lskip
+         \vrule\kern3pt
+         \vbox\bgroup
+             \kern3pt
+             \hsize=\cartinner
+             \baselineskip=\normbskip
+             \lineskip=\normlskip
+             \parskip=\normpskip
+             \vskip -\parskip
+             \comment % For explanation, see the end of def\group.
+}
+\def\Ecartouche{%
+              \ifhmode\par\fi
+             \kern3pt
+         \egroup
+         \kern3pt\vrule
+         \hskip\rskip
+      \egroup
+      \cartbot
+  \egroup
+  \addgroupbox
+  \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+  \aboveenvbreak
+  \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  % Turn off paragraph indentation but redefine \indent to emulate
+  % the normal \indent.
+  \nonfillparindent=\parindent
+  \parindent = 0pt
+  \let\indent\nonfillindent
+  %
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+  \let\exdent=\nofillexdent
+}
+
+\begingroup
+\obeyspaces
+% We want to swallow spaces (but not other tokens) after the fake
+% @indent in our nonfill-environments, where spaces are normally
+% active and set to @tie, resulting in them not being ignored after
+% @indent.
+\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}%
+\gdef\nonfillindentcheck{%
+\ifx\temp %
+\expandafter\nonfillindentgobble%
+\else%
+\leavevmode\nonfillindentbox%
+\fi%
+}%
+\endgroup
+\def\nonfillindentgobble#1{\nonfillindent}
+\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+%    @example, @display, @format, @lisp
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+  \ifx\SETdispenvsize\smallword
+    % end paragraph for sake of leading, in case document has no blank
+    % line.  This is redundant with what happens in \aboveenvbreak, but
+    % we need to do it before changing the fonts, and it's inconvenient
+    % to change the fonts afterward.
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+\def\setsmalldispenv{%
+  \ifx\SETdispenvsize\nosmallword
+  \else
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it in one command.  #1 is the env name, #2 the definition.
+\def\makedispenvdef#1#2{%
+  \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}%
+  \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}%
+  \expandafter\let\csname E#1\endcsname \afterenvbreak
+  \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+  \makedispenvdef{#1}{#3}%
+  \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{lisp}{example}{%
+  \nonfillstart
+  \tt\setupmarkupstyle{example}%
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \gobble % eat return
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenvdef{display}{%
+  \nonfillstart
+  \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{format}{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \advance\leftskip by 0pt plus 1fill\relax
+  \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification.  From plain.tex.
+\envdef\raggedright{%
+  \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax
+}
+\let\Eraggedright\par
+
+\envdef\raggedleft{%
+  \parindent=0pt \leftskip0pt plus2em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedleft\par
+
+\envdef\raggedcenter{%
+  \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedcenter\par
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.  We keep \parskip nonzero in general, since
+% we're doing normal filling.  So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+  \indentedblockstart % same as \indentedblock, but increase right margin too.
+  \ifx\nonarrowing\relax
+    \advance\rightskip by \lispnarrowing
+  \fi
+  \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+  \par
+  \ifx\quotationauthor\thisisundefined\else
+    % indent a bit.
+    \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+  \fi
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty \else
+    {\bf #1: }%
+  \fi
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+%
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \parindent=0pt
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+  \par
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command.  --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996.  The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too.  Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+  \do\ \do\\\do\{\do\}\do\$\do\&%
+  \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+  \do\<\do\>\do\|\do\@\do+\do\"%
+  % Don't do the quotes -- if we do, @set txicodequoteundirected and
+  % @set txicodequotebacktick will not have effect on @verb and
+  % @verbatim, and ?` and !` ligatures won't get disabled.
+  %\do\`\do\'%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+  \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+  \tt  % easiest (and conventionally used) font for verbatim
+  \def\par{\leavevmode\endgraf}%
+  \setupmarkupstyle{verb}%
+  \tabeightspaces
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count
+  % must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion.
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs.  The \global is in case the verbatim line starts with an accent,
+% or some other command that starts with a begin-group.  Otherwise, the
+% entire \verbbox would disappear at the corresponding end-group, before
+% it is typeset.  Meanwhile, we can't have nested verbatim commands
+% (can we?), so the \global won't be overwriting itself.
+\newbox\verbbox
+\def\starttabbox{\global\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabexpand{%
+    \catcode`\^^I=\active
+    \def^^I{\leavevmode\egroup
+      \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+      \divide\dimen\verbbox by\tabw
+      \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+      \advance\dimen\verbbox by\tabw  % advance to next multiple of \tabw
+      \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox
+    }%
+  }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \tt % easiest (and conventionally used) font for verbatim
+  % The \leavevmode here is for blank lines.  Otherwise, we would
+  % never \starttabbox and the \egroup would end verbatim mode.
+  \def\par{\leavevmode\egroup\box\verbbox\endgraf}%
+  \tabexpand
+  \setupmarkupstyle{verbatim}%
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count.
+  % Must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+  \everypar{\starttabbox}%
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters.  Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+%    \def\doverb'{'<char>#1<char>'}'{#1}
+%
+% [Knuth] p. 382; only eat outer {}
+\begingroup
+  \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other
+  \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next]
+\endgroup
+%
+\def\verb{\begingroup\setupverb\doverb}
+%
+%
+% Do the @verbatim magic: define the macro \doverbatim so that
+% the (first) argument ends when '@end verbatim' is reached, ie:
+%
+%     \def\doverbatim#1@end verbatim{#1}
+%
+% For Texinfo it's a lot easier than for LaTeX,
+% because texinfo's \verbatim doesn't stop at '\end{verbatim}':
+% we need not redefine '\', '{' and '}'.
+%
+% Inspired by LaTeX's verbatim command set [latex.ltx]
+%
+\begingroup
+  \catcode`\ =\active
+  \obeylines %
+  % ignore everything up to the first ^^M, that's the newline at the end
+  % of the @verbatim input line itself.  Otherwise we get an extra blank
+  % line in the output.
+  \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}%
+  % We really want {...\end verbatim} in the body of the macro, but
+  % without the active space; thus we have to use \xdef and \gobble.
+\endgroup
+%
+\envdef\verbatim{%
+    \setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+  {%
+    \makevalueexpandable
+    \setupverbatim
+    {%
+      \indexnofonts       % Allow `@@' and other weird things in file names.
+      \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+      \edef\tmp{\noexpand\input #1 }
+      \expandafter
+    }\tmp
+    \afterenvbreak
+  }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+  \begingroup
+    \parindent = 0pt  % paragraph indentation looks wrong on title page
+    \scanexp\copyingtext
+  \endgroup
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+\newcount\defunpenalty
+
+% Start the processing of @deffn:
+\def\startdefun{%
+  \ifnum\lastpenalty<10000
+    \medbreak
+    \defunpenalty=10003 % Will keep this @deffn together with the
+                        % following @def command, see below.
+  \else
+    % If there are two @def commands in a row, we'll have a \nobreak,
+    % which is there to keep the function description together with its
+    % header.  But if there's nothing but headers, we need to allow a
+    % break somewhere.  Check specifically for penalty 10002, inserted
+    % by \printdefunline, instead of 10000, since the sectioning
+    % commands also insert a nobreak penalty, and we don't want to allow
+    % a break between a section heading and a defun.
+    %
+    % As a further refinement, we avoid "club" headers by signalling
+    % with penalty of 10003 after the very first @deffn in the
+    % sequence (see above), and penalty of 10002 after any following
+    % @def command.
+    \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+    %
+    % Similarly, after a section heading, do not allow a break.
+    % But do insert the glue.
+    \medskip  % preceded by discardable penalty, so not a breakpoint
+  \fi
+  %
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+  % First, check whether we are in the right environment:
+  \checkenv#1%
+  %
+  % As above, allow line break if we have multiple x headers in a row.
+  % It's not a great place, though.
+  \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+  %
+  % And now, it's time to reuse the body of the original defun:
+  \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+  \begingroup
+    % call \deffnheader:
+    #1#2 \endheader
+    % common ending:
+    \interlinepenalty = 10000
+    \advance\rightskip by 0pt plus 1fil\relax
+    \endgraf
+    \nobreak\vskip -\parskip
+    \penalty\defunpenalty  % signal to \startdefun and \dodefunx
+    % Some of the @defun-type tags do not enable magic parentheses,
+    % rendering the following check redundant.  But we don't optimize.
+    \checkparencounts
+  \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+  \expandafter\let\csname E#1\endcsname = \Edefun
+  \edef\temp{\noexpand\domakedefun
+    \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+  \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) }
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+  \envdef#1{%
+    \startdefun
+    \doingtypefnfalse    % distinguish typed functions from all else
+    \parseargusing\activeparens{\printdefunline#3}%
+  }%
+  \def#2{\dodefunx#1}%
+  \def#3%
+}
+
+\newif\ifdoingtypefn       % doing typed function?
+\newif\ifrettypeownline    % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line.  This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+%
+\parseargdef\deftypefnnewline{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @txideftypefnnl value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+% \dosubind {index}{topic}{subtopic}
+%
+% If SUBTOPIC is present, precede it with a space, and call \doind.
+% (At some time during the 20th century, this made a two-level entry in an
+% index such as the operation index.  Nobody seemed to notice the change in
+% behaviour though.)
+\def\dosubind#1#2#3{%
+  \def\thirdarg{#3}%
+  \ifx\thirdarg\empty
+    \doind{#1}{#2}%
+  \else
+    \doind{#1}{#2\space#3}%
+  \fi
+}
+
+% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+  \dosubind{fn}{\code{#3}}{#1}%
+  \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{fn}{\code{#4}}{#1}%
+  \doingtypefntrue
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{vr}{\code{#4}}{#1}%
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+% Types:
+
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+  \doind{tp}{\code{#2}}%
+  \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+  \par
+  % Get the values of \leftskip and \rightskip as they were outside the @def...
+  \advance\leftskip by -\defbodyindent
+  %
+  % Determine if we are typesetting the return type of a typed function
+  % on a line by itself.
+  \rettypeownlinefalse
+  \ifdoingtypefn  % doing a typed function specifically?
+    % then check user option for putting return type on its own line:
+    \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+      \rettypeownlinetrue
+    \fi
+  \fi
+  %
+  % How we'll format the category name.  Putting it in brackets helps
+  % distinguish it from the body text that may end up on the next line
+  % just below it.
+  \def\temp{#1}%
+  \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+  %
+  % Figure out line sizes for the paragraph shape.  We'll always have at
+  % least two.
+  \tempnum = 2
+  %
+  % The first line needs space for \box0; but if \rightskip is nonzero,
+  % we need only space for the part of \box0 which exceeds it:
+  \dimen0=\hsize  \advance\dimen0 by -\wd0  \advance\dimen0 by \rightskip
+  %
+  % If doing a return type on its own line, we'll have another line.
+  \ifrettypeownline
+    \advance\tempnum by 1
+    \def\maybeshapeline{0in \hsize}%
+  \else
+    \def\maybeshapeline{}%
+  \fi
+  %
+  % The continuations:
+  \dimen2=\hsize  \advance\dimen2 by -\defargsindent
+  %
+  % The final paragraph shape:
+  \parshape \tempnum  0in \dimen0  \maybeshapeline  \defargsindent \dimen2
+  %
+  % Put the category name at the right margin.
+  \noindent
+  \hbox to 0pt{%
+    \hfil\box0 \kern-\hsize
+    % \hsize has to be shortened this way:
+    \kern\leftskip
+    % Intentionally do not respect \rightskip, since we need the space.
+  }%
+  %
+  % Allow all lines to be underfull without complaint:
+  \tolerance=10000 \hbadness=10000
+  \exdentamount=\defbodyindent
+  {%
+    % defun fonts. We use typewriter by default (used to be bold) because:
+    % . we're printing identifiers, they should be in tt in principle.
+    % . in languages with many accents, such as Czech or French, it's
+    %   common to leave accents off identifiers.  The result looks ok in
+    %   tt, but exceedingly strange in rm.
+    % . we don't want -- and --- to be treated as ligatures.
+    % . this still does not fix the ?` and !` ligatures, but so far no
+    %   one has made identifiers using them :).
+    \df \tt
+    \def\temp{#2}% text of the return type
+    \ifx\temp\empty\else
+      \tclose{\temp}% typeset the return type
+      \ifrettypeownline
+        % put return type on its own line; prohibit line break following:
+        \hfil\vadjust{\nobreak}\break
+      \else
+        \space  % type on same line, so just followed by a space
+      \fi
+    \fi           % no return type
+    #3% output function name
+  }%
+  {\rm\enskip}% hskip 0.5 em of \rmfont
+  %
+  \boldbrax
+  % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name.  This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable.  Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+  % use sl by default (not ttsl),
+  % tt for the names.
+  \df \sl \hyphenchar\font=0
+  %
+  % On the other hand, if an argument has two dashes (for instance), we
+  % want a way to get ttsl.  We used to recommend @var for that, so
+  % leave the code in, but it's strange for @var to lead to typewriter.
+  % Nowadays we recommend @code, since the difference between a ttsl hyphen
+  % and a tt hyphen is pretty tiny.  @code also disables ?` !`.
+  \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}%
+  #1%
+  \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+  \catcode`\(=\active \catcode`\)=\active
+  \catcode`\[=\active \catcode`\]=\active
+  \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+  \activeparens
+  \global\let(=\lparen \global\let)=\rparen
+  \global\let[=\lbrack \global\let]=\rbrack
+  \global\let& = \&
+
+  \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+  \gdef\magicamp{\let&=\amprm}
+}
+\let\ampchar\&
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+  \ifampseen
+    % At the first level, print parens in roman,
+    % otherwise use the default font.
+    \ifnum \parencount=1 \rm \fi
+  \else
+    % The \sf parens (in \boldbrax) actually are a little bolder than
+    % the contained text.  This is especially needed for [ and ] .
+    \sf
+  \fi
+}
+\def\infirstlevel#1{%
+  \ifampseen
+    \ifnum\parencount=1
+      #1%
+    \fi
+  \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+  \global\advance\parencount by 1
+  {\parenfont(}%
+  \infirstlevel \bfafterword
+}
+\def\clnr{%
+  {\parenfont)}%
+  \infirstlevel \sl
+  \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+  \global\advance\brackcount by 1
+  {\bf[}%
+}
+\def\rbrb{%
+  {\bf]}%
+  \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+  \ifnum\parencount=0 \else \badparencount \fi
+  \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+% these should not use \errmessage; the glibc manual, at least, actually
+% has such constructs (when documenting function pointers).
+\def\badparencount{%
+  \message{Warning: unbalanced parentheses in @def...}%
+  \global\parencount=0
+}
+\def\badbrackcount{%
+  \message{Warning: unbalanced square brackets in @def...}%
+  \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\thisisundefined
+  \newwrite\macscribble
+  \def\scantokens#1{%
+    \toks0={#1}%
+    \immediate\openout\macscribble=\jobname.tmp
+    \immediate\write\macscribble{\the\toks0}%
+    \immediate\closeout\macscribble
+    \input \jobname.tmp
+  }
+\fi
+
+% Used at the time of macro expansion.
+% Argument is macro body with arguments substituted
+\def\scanmacro#1{%
+  \newlinechar`\^^M
+  \def\xeatspaces{\eatspaces}%
+  %
+  % Process the macro body under the current catcode regime.
+  \scantokens{#1@comment}%
+  %
+  % The \comment is to remove the \newlinechar added by \scantokens, and
+  % can be noticed by \parsearg.  Note \c isn't used because this means cedilla
+  % in math mode.
+}
+
+% Used for copying and captions
+\def\scanexp#1{%
+  \expandafter\scanmacro\expandafter{#1}%
+}
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% List of all defined macros in the form
+%    \commondummyword\macro1\commondummyword\macro2...
+% Currently is also contains all @aliases; the list can be split
+% if there is a need.
+\def\macrolist{}
+
+% Add the macro to \macrolist
+\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
+\def\addtomacrolistxxx#1{%
+     \toks0 = \expandafter{\macrolist\commondummyword#1}%
+     \xdef\macrolist{\the\toks0}%
+}
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+%   \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+  \expandafter\let
+  \csname#1\expandafter\endcsname
+  \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion.  Must do this non-globally, to
+% confine the change to the current group.
+%
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+%
+\def\scanctxt{% used as subroutine
+  \catcode`\"=\other
+  \catcode`\+=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\^=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\~=\other
+  \passthroughcharstrue
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\\=\other
+  \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+  \scanctxt
+  \catcode`\ =\other
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \catcode`\}=\other
+  \catcode`\^^M=\other
+  \usembodybackslash
+}
+
+% Used when scanning braced macro arguments.  Note, however, that catcode
+% changes here are ineffectual if the macro invocation was nested inside
+% an argument to another Texinfo command.
+\def\macroargctxt{%
+  \scanctxt
+  \catcode`\ =\active
+  \catcode`\@=\other
+  \catcode`\^^M=\other
+  \catcode`\\=\active
+}
+
+\def\macrolineargctxt{% used for whole-line arguments without braces
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \catcode`\}=\other
+}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+%
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\margbackslash#1{\char`\#1 }
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}% now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0\relax
+  \else
+     \expandafter\parsemargdef \argl;%
+     \if\paramno>256\relax
+       \ifx\eTeXversion\thisisundefined
+         \errhelp = \EMsimple
+         \errmessage{You need eTeX to compile a file with macros with more 
than 256 arguments}
+       \fi
+     \fi
+  \fi
+  \if1\csname ismacro.\the\macname\endcsname
+     \message{Warning: redefining \the\macname}%
+  \else
+     \expandafter\ifx\csname \the\macname\endcsname \relax
+     \else \errmessage{Macro name \the\macname\space already defined}\fi
+     \global\cslet{macsave.\the\macname}{\the\macname}%
+     \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+     \addtomacrolist{\the\macname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody
+  \fi}
+
+\parseargdef\unmacro{%
+  \if1\csname ismacro.#1\endcsname
+    \global\cslet{#1}{macsave.#1}%
+    \global\expandafter\let \csname ismacro.#1\endcsname=0%
+    % Remove the macro name from \macrolist:
+    \begingroup
+      \expandafter\let\csname#1\endcsname \relax
+      \let\commondummyword\unmacrodo
+      \xdef\macrolist{\macrolist}%
+    \endgroup
+  \else
+    \errmessage{Macro #1 not defined}%
+  \fi
+}
+
+% Called by \do from \dounmacro on each macro.  The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+  \ifx #1\relax
+    % remove this
+  \else
+    \noexpand\commondummyword \noexpand#1%
+  \fi
+}
+
+% \getargs -- Parse the arguments to a @macro line.  Set \macname to
+% the name of the macro, and \argl to the braced argument list.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname#1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+% This made use of the feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+
+% Parse the optional {params} list to @macro or @rmacro.
+% Set \paramno to the number of arguments,
+% and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a
+% three-param macro.)  Define \macarg.BLAH for each BLAH in the params
+% list to some hook where the argument is to be expanded.  If there are
+% less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.
+%
+% That gets used by \mbodybackslash (above).
+%
+% If there are 10 or more arguments, a different technique is used: see
+% \parsemmanyargdef.
+%
+\def\parsemargdef#1;{%
+  \paramno=0\def\paramlist{}%
+  \let\hash\relax
+  % \hash is redefined to `#' later to get it into definitions
+  \let\xeatspaces\relax
+  \parsemargdefxxx#1,;,%
+  \ifnum\paramno<10\relax\else
+    \paramno0\relax
+    \parsemmanyargdef@@#1,;,% 10 or more arguments
+  \fi
+}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+
+% \parsemacbody, \parsermacbody
+%
+% Read recursive and nonrecursive macro bodies. (They're different since
+% rec and nonrec macros end differently.)
+%
+% We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro
+% body to be transformed.
+% Set \macrobody to the body of the macro, and call \defmacro.
+%
+{\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+{\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+
+% Make @ a letter, so that we can make private-to-Texinfo macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+%%%%%%%%%%%%%% Code for > 10 arguments only   %%%%%%%%%%%%%%%%%%
+
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef the body (nothing else will expand because of
+% the catcode regime under which the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, no macro can have more than 256 arguments (else error).
+%
+% In case that there are 10 or more arguments we parse again the arguments
+% list to set new definitions for the \macarg.BLAH macros corresponding to
+% each BLAH argument. It was anyhow needed to parse already once this list
+% in order to count the arguments, and as macros with at most 9 arguments
+% are by far more frequent than macro with 10 or more arguments, defining
+% twice the \macarg.BLAH macros does not cost too much processing power.
+\def\parsemmanyargdef@@#1,{%
+  \if#1;\let\next=\relax
+  \else
+    \let\next=\parsemmanyargdef@@
+    \edef\tempb{\eatspaces{#1}}%
+    \expandafter\def\expandafter\tempa
+       \expandafter{\csname macarg.\tempb\endcsname}%
+    % Note that we need some extra \noexpand\noexpand, this is because we
+    % don't want \the  to be expanded in the \parsermacbody  as it uses an
+    % \xdef .
+    \expandafter\edef\tempa
+      {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+    \advance\paramno by 1\relax
+  \fi\next}
+
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition.  It gets all the arguments' values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+  \def\macargdeflist@{}%
+  \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+  \def\paramlist{#2,\nil@}%
+  \def\macroname{#1}%
+  \begingroup
+  \macroargctxt
+  \def\argvaluelist{#3,\nil@}%
+  \def\@tempa{#3}%
+  \ifx\@tempa\empty
+    \setemptyargvalues@
+  \else
+    \getargvals@@
+  \fi
+}
+\def\getargvals@@{%
+  \ifx\paramlist\nilm@
+      % Some sanity check needed here that \argvaluelist is also empty.
+      \ifx\argvaluelist\nillm@
+      \else
+        \errhelp = \EMsimple
+        \errmessage{Too many arguments in macro `\macroname'!}%
+      \fi
+      \let\next\macargexpandinbody@
+  \else
+    \ifx\argvaluelist\nillm@
+       % No more arguments values passed to macro.  Set remaining named-arg
+       % macros to empty.
+       \let\next\setemptyargvalues@
+    \else
+      % pop current arg name into \@tempb
+      \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\paramlist}%
+       % pop current argument value into \@tempc
+      \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\argvaluelist}%
+       % Here \@tempb is the current arg name and \@tempc is the current arg 
value.
+       % First place the new argument macro definition into \@tempd
+       \expandafter\macname\expandafter{\@tempc}%
+       \expandafter\let\csname macarg.\@tempb\endcsname\relax
+       \expandafter\def\expandafter\@tempe\expandafter{%
+         \csname macarg.\@tempb\endcsname}%
+       \edef\@tempd{\long\def\@tempe{\the\macname}}%
+       \push@\@tempd\macargdeflist@
+       \let\next\getargvals@@
+    \fi
+  \fi
+  \next
+}
+
+\def\push@#1#2{%
+  \expandafter\expandafter\expandafter\def
+  \expandafter\expandafter\expandafter#2%
+  \expandafter\expandafter\expandafter{%
+  \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa.
+%
+\def\macvalstoargs@{%
+  %  To do this we use the property that token registers that are \the'ed
+  % within an \edef  expand only once. So we are going to place all argument
+  % values into respective token registers.
+  %
+  % First we save the token context, and initialize argument numbering.
+  \begingroup
+    \paramno0\relax
+    % Then, for each argument number #N, we place the corresponding argument
+    % value into a new token list register \toks#N
+    \expandafter\putargsintokens@\saveparamlist@,;,%
+    % Then, we expand the body so that argument are replaced by their
+    % values. The trick for values not to be expanded themselves is that they
+    % are within tokens and that tokens expand only once in an \edef .
+    \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+    % Now we restore the token stack pointer to free the token list registers
+    % which we have used, but we make sure that expanded body is saved after
+    % group.
+    \expandafter
+  \endgroup
+  \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+  }
+
+% Define the named-macro outside of this group and then close this group.
+%
+\def\macargexpandinbody@{%
+  \expandafter
+  \endgroup
+  \macargdeflist@
+  % First the replace in body the macro arguments by their values, the result
+  % is in \@tempa .
+  \macvalstoargs@
+  % Then we point at the \norecurse or \gobble (for recursive) macro value
+  % with \@tempb .
+  \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+  % Depending on whether it is recursive or not, we need some tailing
+  % \egroup .
+  \ifx\@tempb\gobble
+     \let\@tempc\relax
+  \else
+     \let\@tempc\egroup
+  \fi
+  % And now we do the real job:
+  
\edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+  \@tempd
+}
+
+\def\putargsintokens@#1,{%
+  \if#1;\let\next\relax
+  \else
+    \let\next\putargsintokens@
+    % First we allocate the new token list register, and give it a temporary
+    % alias \@tempb .
+    \toksdef\@tempb\the\paramno
+    % Then we place the argument value into that token list register.
+    \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+    \expandafter\@tempb\expandafter{\@tempa}%
+    \advance\paramno by 1\relax
+  \fi
+  \next
+}
+
+% Trailing missing arguments are set to empty.
+%
+\def\setemptyargvalues@{%
+  \ifx\paramlist\nilm@
+    \let\next\macargexpandinbody@
+  \else
+    \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+    \let\next\setemptyargvalues@
+  \fi
+  \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+  \expandafter\def\expandafter\@tempa\expandafter{%
+    \expandafter\def\csname macarg.#1\endcsname{}}%
+  \push@\@tempa\macargdeflist@
+  \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+   \def#1{#3}%
+   \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+   \long\def#1{#3}%
+   \long\def#2{#4}%
+}
+
+
+%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%%
+
+
+% This defines a Texinfo @macro or @rmacro, called by \parsemacbody.
+%    \macrobody has the body of the macro in it, with placeholders for
+% its parameters, looking like "\xeatspaces{\hash 1}".
+%    \paramno is the number of parameters
+%    \paramlist is a TeX parameter text, e.g. "#1,#2,#3,"
+% There are four cases: macros of zero, one, up to nine, and many arguments.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in: @include reads the file inside a group.
+%
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifnum\paramno=1
+    \def\xeatspaces##1{##1}%
+    % This removes the pair of braces around the argument.  We don't
+    % use \eatspaces, because this can cause ends of lines to be lost
+    % when the argument to \eatspaces is read, leading to line-based
+    % commands like "@itemize" not being read correctly.
+  \else
+    \let\xeatspaces\relax % suppress expansion
+  \fi
+  \ifcase\paramno
+  % 0
+    \expandafter\xdef\csname\the\macname\endcsname{%
+      \bgroup
+        \noexpand\spaceisspace
+        \noexpand\endlineisspace
+        \noexpand\expandafter % skip any whitespace after the macro name.
+        \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}}%
+  \or % 1
+    \expandafter\xdef\csname\the\macname\endcsname{%
+       \bgroup
+       \noexpand\braceorline
+       \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}%
+      }%
+  \else % at most 9
+    \ifnum\paramno<10\relax
+      % @MACNAME sets the context for reading the macro argument
+      % @MACNAME@@ gets the argument, processes backslashes and appends a
+      % comma.
+      % @MACNAME@@@ removes braces surrounding the argument list.
+      % @MACNAME@@@@ scans the macro body with arguments substituted.
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \bgroup
+        \noexpand\expandafter  % This \expandafter skip any spaces after the
+        \noexpand\macroargctxt % macro before we change the catcode of space.
+        \noexpand\expandafter
+        \expandafter\noexpand\csname\the\macname @@\endcsname}%
+      \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+          \noexpand\passargtomacro
+          \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+      \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname @@@@\endcsname\paramlist{%
+          \egroup\noexpand\scanmacro{\macrobody}}%
+    \else % 10 or more:
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\getargvals@{\the\macname}{\argl}%
+      }%
+      \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+      \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+    \fi
+  \fi}
+
+\catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+{\catcode`\@=0 \catcode`\\=13  % We need to manipulate \ so use @ as escape
+@catcode`@_=11  % private names
+@catcode`@!=11  % used as argument separator
+
+% \passargtomacro#1#2 -
+% Call #1 with a list of tokens #2, with any doubled backslashes in #2
+% compressed to one.
+%
+% This implementation works by expansion, and not execution (so we cannot use
+% \def or similar).  This reduces the risk of this failing in contexts where
+% complete expansion is done with no execution (for example, in writing out to
+% an auxiliary file for an index entry).
+%
+% State is kept in the input stream: the argument passed to
+% @look_ahead, @gobble_and_check_finish and @add_segment is
+%
+% THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN  (... rest of input)
+%
+% where:
+% THE_MACRO - name of the macro we want to call
+% ARG_RESULT - argument list we build to pass to that macro
+% PENDING_BS - either a backslash or nothing
+% NEXT_TOKEN - used to look ahead in the input stream to see what's coming next
+
+@gdef@passargtomacro#1#2{%
+  @add_segment #1!{}@relax#2\@_finish\%
+}
+@gdef@_finish{@_finishx} @global@let@_finishx@relax
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 used to look ahead
+%
+% If the next token is not a backslash, process the rest of the argument;
+% otherwise, remove the next token.
+@gdef@look_ahead#1!#2#3#4{%
+  @ifx#4\%
+   @expandafter@gobble_and_check_finish
+  @else
+   @expandafter@add_segment
+  @fi#1!{#2}#4#4%
+}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 should be a backslash, which is gobbled.
+% #5 looks ahead
+%
+% Double backslash found.  Add a single backslash, and look ahead.
+@gdef@gobble_and_check_finish#1!#2#3#4#5{%
+  @add_segment#1\!{}#5#5%
+}
+
+@gdef@is_fi{@fi}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 is input stream until next backslash
+%
+% Input stream is either at the start of the argument, or just after a
+% backslash sequence, either a lone backslash, or a doubled backslash.
+% NEXT_TOKEN contains the first token in the input stream: if it is \finish,
+% finish; otherwise, append to ARG_RESULT the segment of the argument up until
+% the next backslash.  PENDING_BACKSLASH contains a backslash to represent
+% a backslash just before the start of the input stream that has not been
+% added to ARG_RESULT.
+@gdef@add_segment#1!#2#3#4\{%
+@ifx#3@_finish
+  @call_the_macro#1!%
+@else
+  % append the pending backslash to the result, followed by the next segment
+  @expandafter@is_fi@look_ahead#1#2#4!{\}@fi
+  % this @fi is discarded by @look_ahead.
+  % we can't get rid of it with \expandafter because we don't know how
+  % long #4 is.
+}
+
+% #1 - THE_MACRO
+% #2 - ARG_RESULT
+% #3 discards the res of the conditional in @add_segment, and @is_fi ends the
+% conditional.
+@gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}}
+
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% \braceorline MAC is used for a one-argument macro MAC.  It checks
+% whether the next non-whitespace character is a {.  It sets the context
+% for reading the argument (slightly different in the two cases).  Then,
+% to read the argument, in the whole-line case, it then calls the regular
+% \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC.
+%
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup
+    \macroargctxt
+    \expandafter\passargtomacro
+  \else
+    \macrolineargctxt\expandafter\parsearg
+  \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign.  Make them active and then expand them all to nothing.
+%
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+  {%
+    \expandafter\let\obeyedspace=\empty
+    \addtomacrolist{#1}%
+    \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+  }%
+  \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{%
+  \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references.  The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross,  ,  , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}\omittopnode}
+
+% Used so that the @top node doesn't have to be wrapped in an @ifnottex
+% conditional.
+% \doignore goes to more effort to skip nested conditionals but we don't need
+% that here.
+\def\omittopnode{%
+   \ifx\lastnode\wordTop
+   \expandafter\ignorenode\fi
+}
+\def\wordTop{Top}
+
+% Until the next @node or @bye command, divert output to a box that is not
+% output.
+\def\ignorenode{\setbox\dummybox\vbox\bgroup\def\node{\egroup\node}%
+\ignorenodebye
+}
+
+{\let\bye\relax
+\gdef\ignorenodebye{\let\bye\ignorenodebyedef}
+\gdef\ignorenodebyedef{\egroup(`Top' node ignored)\bye}}
+% The redefinition of \bye here is because it is declared \outer
+
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node.  #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+  \ifx\lastnode\empty\else
+    \setref{\lastnode}{#1}%
+    \global\let\lastnode=\empty
+  \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \currentsection,
+%                 or the anchor name.
+% 2) NAME-snt   - section number and type, passed as the SNT arg, or
+%                 empty for anchors.
+% 3) NAME-pg    - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat.  In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof   - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+  \pdfmkdest{#1}%
+  \iflinks
+    {%
+      \requireauxfile
+      \atdummies  % preserve commands, but don't expand them
+      % match definition in \xrdef, \refx, \xrefX.
+      \def\value##1{##1}%
+      \edef\writexrdef##1##2{%
+       \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+         ##1}{##2}}% these are parameters of \writexrdef
+      }%
+      \toks0 = \expandafter{\currentsection}%
+      \immediate \writexrdef{title}{\the\toks0 }%
+      \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+      \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
+    }%
+  \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+%
+\parseargdef\xrefautomaticsectiontitle{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+%
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref{\putwordsee{} \xrefXX}
+\def\xref{\putwordSee{} \xrefXX}
+\def\ref{\xrefXX}
+
+\def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX}
+\def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \unsepspaces
+  %
+  % Get args without leading/trailing spaces.
+  \def\printedrefname{\ignorespaces #3}%
+  \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+  %
+  \def\infofilename{\ignorespaces #4}%
+  \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+  %
+  \def\printedmanual{\ignorespaces #5}%
+  \setbox\printedmanualbox  = \hbox{\printedmanual\unskip}%
+  %
+  % If the printed reference name (arg #3) was not explicitly given in
+  % the @xref, figure out what we want to use.
+  \ifdim \wd\printedrefnamebox = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+      % Not auto section-title: use node name inside the square brackets.
+      \def\printedrefname{\ignorespaces #1}%
+    \else
+      % Auto section-title: use chapter/section title inside
+      % the square brackets if we have it.
+      \ifdim \wd\printedmanualbox > 0pt
+        % It is in another manual, so we don't have it; use node name.
+        \def\printedrefname{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We (should) know the real title if we have the xref values.
+          \def\printedrefname{\refx{#1-title}{}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printedrefname{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % Make link in pdf output.
+  \ifpdf
+    % For pdfTeX and LuaTeX
+    {\indexnofonts
+     \makevalueexpandable
+     \turnoffactive
+     % This expands tokens, so do it after making catcode changes, so _
+     % etc. don't get their TeX definitions.  This ignores all spaces in
+     % #4, including (wrongly) those in the middle of the filename.
+     \getfilename{#4}%
+     %
+     % This (wrongly) does not take account of leading or trailing
+     % spaces in #1, which should be ignored.
+     \setpdfdestname{#1}%
+     %
+     \ifx\pdfdestname\empty
+       \def\pdfdestname{Top}% no empty targets
+     \fi
+     %
+     \leavevmode
+     \startlink attr{/Border [0 0 0]}%
+     \ifnum\filenamelength>0
+       goto file{\the\filename.pdf} name{\pdfdestname}%
+     \else
+       goto name{\pdfmkpgn{\pdfdestname}}%
+     \fi
+    }%
+    \setcolor{\linkcolor}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+    \else
+      % For XeTeX
+      {\indexnofonts
+       \makevalueexpandable
+       \turnoffactive
+       % This expands tokens, so do it after making catcode changes, so _
+       % etc. don't get their TeX definitions.  This ignores all spaces in
+       % #4, including (wrongly) those in the middle of the filename.
+       \getfilename{#4}%
+       %
+       % This (wrongly) does not take account of leading or trailing
+       % spaces in #1, which should be ignored.
+       \setpdfdestname{#1}%
+       %
+       \ifx\pdfdestname\empty
+         \def\pdfdestname{Top}% no empty targets
+       \fi
+       %
+       \leavevmode
+       \ifnum\filenamelength>0
+         % With default settings,
+         % XeTeX (xdvipdfmx) replaces link destination names with integers.
+         % In this case, the replaced destination names of
+         % remote PDFs are no longer known.  In order to avoid a replacement,
+         % you can use xdvipdfmx's command line option `-C 0x0010'.
+         % If you use XeTeX 0.99996+ (TeX Live 2016+),
+         % this command line option is no longer necessary
+         % because we can use the `dvipdfmx:config' special.
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}%
+       \else
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoTo /D (\pdfdestname) >> >>}%
+       \fi
+      }%
+      \setcolor{\linkcolor}%
+    \fi
+  \fi
+  {%
+    % Have to otherify everything special to allow the \csname to
+    % include an _ in the xref name, etc.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+      \csname XR#1-title\endcsname
+  }%
+  %
+  % Float references are printed completely differently: "Figure 1.2"
+  % instead of "[somenode], p.3".  \iffloat distinguishes them by
+  % \Xthisreftitle being set to a magic string.
+  \iffloat\Xthisreftitle
+    % If the user specified the print name (third arg) to the ref,
+    % print it instead of our usual "Figure 1.2".
+    \ifdim\wd\printedrefnamebox = 0pt
+      \refx{#1-snt}{}%
+    \else
+      \printedrefname
+    \fi
+    %
+    % If the user also gave the printed manual name (fifth arg), append
+    % "in MANUALNAME".
+    \ifdim \wd\printedmanualbox > 0pt
+      \space \putwordin{} \cite{\printedmanual}%
+    \fi
+  \else
+    % node/anchor (non-float) references.
+    %
+    % If we use \unhbox to print the node names, TeX does not insert
+    % empty discretionaries after hyphens, which means that it will not
+    % find a line break at a hyphen in a node names.  Since some manuals
+    % are best written with fairly long node names, containing hyphens,
+    % this is a loss.  Therefore, we give the text of the node name
+    % again, so it is as if TeX is seeing it for the first time.
+    %
+    \ifdim \wd\printedmanualbox > 0pt
+      % Cross-manual reference with a printed manual name.
+      %
+      \crossmanualxref{\cite{\printedmanual\unskip}}%
+    %
+    \else\ifdim \wd\infofilenamebox > 0pt
+      % Cross-manual reference with only an info filename (arg 4), no
+      % printed manual name (arg 5).  This is essentially the same as
+      % the case above; we output the filename, since we have nothing else.
+      %
+      \crossmanualxref{\code{\infofilename\unskip}}%
+    %
+    \else
+      % Reference within this manual.
+      %
+      % Only output a following space if the -snt ref is nonempty; for
+      % @unnumbered and @anchor, it won't be.
+      \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+      \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+      %
+      % output the `[mynode]' via the macro below so it can be overridden.
+      \xrefprintnodename\printedrefname
+      %
+      % But we always want a comma and a space:
+      ,\space
+      %
+      % output the `page 3'.
+      \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+      % Add a , if xref followed by a space
+      \if\space\noexpand\tokenafterxref ,%
+      \else\ifx\       \tokenafterxref ,% @TAB
+      \else\ifx\*\tokenafterxref ,%   @*
+      \else\ifx\ \tokenafterxref ,%   @SPACE
+      \else\ifx\
+                \tokenafterxref ,%    @NL
+      \else\ifx\tie\tokenafterxref ,% @tie
+      \fi\fi\fi\fi\fi\fi
+    \fi\fi
+  \fi
+  \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1.  Used just above (twice).
+%
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top.  Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+%
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input.  By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font).  Hopefully it will never happen in practice.
+%
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+%
+\def\crossmanualxref#1{%
+  \setbox\toprefbox = \hbox{Top\kern7sp}%
+  \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+  \ifdim \wd2 > 7sp  % nonempty?
+    \ifdim \wd2 = \wd\toprefbox \else  % same as Top?
+      \putwordSection{} ``\printedrefname'' \putwordin{}\space
+    \fi
+  \fi
+  #1%
+}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output.  It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents.  Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+  \ifnum\secno=0
+    \putwordChapter@tie \the\chapno
+  \else \ifnum\subsecno=0
+    \putwordSection@tie \the\chapno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+\def\Yappendix{%
+  \ifnum\secno=0
+     \putwordAppendix@tie @char\the\appendixno{}%
+  \else \ifnum\subsecno=0
+     \putwordSection@tie @char\the\appendixno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie
+      @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+
+% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME.  SUFFIX
+% is output afterwards if non-empty.
+\def\refx#1#2{%
+  \requireauxfile
+  {%
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter\thisrefX
+      \csname XR#1\endcsname
+  }%
+  \ifx\thisrefX\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        {\toks0 = {#1}% avoid expansion of possibly-complex value
+         \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \thisrefX
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.  Define a control
+% sequence for a cross-reference target (we prepend XR to the control sequence
+% name to avoid collisions).  The value is the page number.  If this is a float
+% type, we have more work to do.
+%
+\def\xrdef#1#2{%
+  {% Expand the node or anchor name to remove control sequences.
+   % \turnoffactive stops 8-bit characters being changed to commands
+   % like @'e.  \refx does the same to retrieve the value in the definition.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \xdef\safexrefname{#1}%
+  }%
+  %
+  \bgroup
+    \expandafter\gdef\csname XR\safexrefname\endcsname{#2}%
+  \egroup
+  % We put the \gdef inside a group to avoid the definitions building up on
+  % TeX's save stack, which can cause it to run out of space for aux files with
+  % thousands of lines.  \gdef doesn't use the save stack, but \csname does
+  % when it defines an unknown control sequence as \relax.
+  %
+  % Was that xref control sequence that we just defined for a float?
+  \expandafter\iffloat\csname XR\safexrefname\endcsname
+    % it was a float, and we have the (safe) float type in \iffloattype.
+    \expandafter\let\expandafter\floatlist
+      \csname floatlist\iffloattype\endcsname
+    %
+    % Is this the first time we've seen this float type?
+    \expandafter\ifx\floatlist\relax
+      \toks0 = {\do}% yes, so just \do
+    \else
+      % had it before, so preserve previous elements in list.
+      \toks0 = \expandafter{\floatlist\do}%
+    \fi
+    %
+    % Remember this xref in the control sequence \floatlistFLOATTYPE,
+    % for later use in \listoffloats.
+    \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0
+      {\safexrefname}}%
+  \fi
+}
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate at the beginning of the file.
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% Used when writing to the aux file, or when using data from it.
+\def\requireauxfile{%
+  \iflinks
+    \tryauxfile
+    % Open the new aux file.  TeX will close it automatically at exit.
+    \immediate\openout\auxfile=\jobname.aux
+  \fi
+  \global\let\requireauxfile=\relax   % Only do this once.
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+%
+\def\tryauxfile{%
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \readdatafile{aux}%
+    \global\havexrefstrue
+  \fi
+  \closein 1
+}
+
+\def\setupdatafile{%
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  \catcode`\^=\other
+  %
+  % Special characters.  Should be turned off anyway, but...
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`\%=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  %
+  \catcode`\\=\active
+  %
+  % @ is our escape character in .aux files, and we need braces.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\@=0
+}
+
+\def\readdatafile#1{%
+\begingroup
+  \setupdatafile
+  \input\jobname.#1
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for Info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\gdef\dofootnote{%
+  \insert\footins\bgroup
+  %
+  % Nested footnotes are not supported in TeX, that would take a lot
+  % more work.  (\startsavinginserts does not suffice.)
+  \let\footnote=\errfootnotenest
+  %
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \hsize=\txipagewidth
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  \smallfonts \rm
+  %
+  % Because we use hanging indentation in footnotes, a @noindent appears
+  % to exdent this text, so make it be a no-op.  makeinfo does not use
+  % hanging indentation so @noindent can still be needed within footnote
+  % text after an @example or the like (not that this is good style).
+  \let\noindent = \relax
+  %
+  % Hang the footnote text off the number.  Use \everypar in case the
+  % footnote extends for more than one paragraph.
+  \everypar = {\hang}%
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  %
+  % Invoke rest of plain TeX footnote routine.
+  \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+\def\errfootnotenest{%
+  \errhelp=\EMsimple
+  \errmessage{Nested footnotes not supported in texinfo.tex,
+    even though they work in makeinfo; sorry}
+}
+
+\def\errfootnoteheading{%
+  \errhelp=\EMsimple
+  \errmessage{Footnotes in chapters, sections, etc., are not supported}
+}
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished.  Otherwise, the insertion
+% would be lost.
+% Similarly, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes.  --kasal, 16nov03.
+%
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+  \ifx \insert\ptexinsert
+    \let\insert\saveinsert
+  \else
+    \let\checkinserts\relax
+  \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+  \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+  \afterassignment\next
+  % swallow the left brace
+  \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+  \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+    {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+  \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials  %  ;-)
+  \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+  \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+  \next
+}
+\def\newsaveinsX #1{%
+  \csname newbox\endcsname #1%
+  \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+    \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  % Do not bother showing banner with epsf.tex v2.7k (available in
+  % doc/epsf.tex and on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from https://ctan.org/texarchive/macros/texinfo/texinfo/doc/epsf.tex.}
+%
+\def\image#1{%
+  \ifx\epsfbox\thisisundefined
+    \ifwarnednoepsf \else
+      \errhelp = \noepsfhelp
+      \errmessage{epsf.tex not found, images will be ignored}%
+      \global\warnednoepsftrue
+    \fi
+  \else
+    \imagexxx #1,,,,,\finish
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+  \catcode`\^^M = 5     % in case we're inside an example
+  \normalturnoffactive  % allow _ et al. in names
+  \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro
+  % If the image is by itself, center it.
+  \ifvmode
+    \imagevmodetrue
+  \else \ifx\centersub\centerV
+    % for @center @image, we need a vbox so we can have our vertical space
+    \imagevmodetrue
+    \vbox\bgroup % vbox has better behavior than vtop herev
+  \fi\fi
+  %
+  \ifimagevmode
+    \nobreak\medskip
+    % Usually we'll have text after the image which will insert
+    % \parskip glue, so insert it here too to equalize the space
+    % above and below.
+    \nobreak\vskip\parskip
+    \nobreak
+  \fi
+  %
+  % Leave vertical mode so that indentation from an enclosing
+  %  environment such as @quotation is respected.
+  % However, if we're at the top level, we don't want the
+  %  normal paragraph indentation.
+  % On the other hand, if we are in the case of @center @image, we don't
+  %  want to start a paragraph, which will create a hsize-width box and
+  %  eradicate the centering.
+  \ifx\centersub\centerV\else \noindent \fi
+  %
+  % Output the image.
+  \ifpdf
+    % For pdfTeX and LuaTeX <= 0.80
+    \dopdfimage{#1}{#2}{#3}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      % For epsf.tex
+      % \epsfbox itself resets \epsf?size at each figure.
+      \setbox0 = \hbox{\ignorespaces #2}%
+        \ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+      \setbox0 = \hbox{\ignorespaces #3}%
+        \ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+      \epsfbox{#1.eps}%
+    \else
+      % For XeTeX
+      \doxeteximage{#1}{#2}{#3}%
+    \fi
+  \fi
+  %
+  \ifimagevmode
+    \medskip  % space after a standalone image
+  \fi
+  \ifx\centersub\centerV \egroup \fi
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc.  We don't actually implement floating yet, we always include the
+% float "here".  But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc.  Can't contain commas.  If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label.  Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored.  It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+  \let\thiscaption=\empty
+  \let\thisshortcaption=\empty
+  %
+  % don't lose footnotes inside @float.
+  %
+  % BEWARE: when the floats start float, we have to issue warning whenever an
+  % insert appears inside a float which could possibly float. --kasal, 26may04
+  %
+  \startsavinginserts
+  %
+  % We can't be used inside a paragraph.
+  \par
+  %
+  \vtop\bgroup
+    \def\floattype{#1}%
+    \def\floatlabel{#2}%
+    \def\floatloc{#3}% we do nothing with this yet.
+    %
+    \ifx\floattype\empty
+      \let\safefloattype=\empty
+    \else
+      {%
+        % the floattype might have accents or other special characters,
+        % but we need to use it in a control sequence name.
+        \indexnofonts
+        \turnoffactive
+        \xdef\safefloattype{\floattype}%
+      }%
+    \fi
+    %
+    % If label is given but no type, we handle that as the empty type.
+    \ifx\floatlabel\empty \else
+      % We want each FLOATTYPE to be numbered separately (Figure 1,
+      % Table 1, Figure 2, ...).  (And if no label, no number.)
+      %
+      \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+      \global\advance\floatno by 1
+      %
+      {%
+        % This magic value for \currentsection is output by \setref as the
+        % XREFLABEL-title value.  \xrefX uses it to distinguish float
+        % labels (which have a completely different output format) from
+        % node and anchor labels.  And \xrdef uses it to construct the
+        % lists of floats.
+        %
+        \edef\currentsection{\floatmagic=\safefloattype}%
+        \setref{\floatlabel}{Yfloat}%
+      }%
+    \fi
+    %
+    % start with \parskip glue, I guess.
+    \vskip\parskip
+    %
+    % Don't suppress indentation if a float happens to start a section.
+    \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption:    Foo 1.1
+% @float Foo & @caption{Cap}:     Foo: Cap
+% @float Foo & no caption:        Foo
+% @float ,lbl & Caption{Cap}:     1.1: Cap
+% @float ,lbl & no caption:       1.1
+% @float & @caption{Cap}:         Cap
+% @float & no caption:
+%
+\def\Efloat{%
+    \let\floatident = \empty
+    %
+    % In all cases, if we have a float type, it comes first.
+    \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+    %
+    % If we have an xref label, the number comes next.
+    \ifx\floatlabel\empty \else
+      \ifx\floattype\empty \else % if also had float type, need tie first.
+        \appendtomacro\floatident{\tie}%
+      \fi
+      % the number.
+      \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+    \fi
+    %
+    % Start the printed caption with what we've constructed in
+    % \floatident, but keep it separate; we need \floatident again.
+    \let\captionline = \floatident
+    %
+    \ifx\thiscaption\empty \else
+      \ifx\floatident\empty \else
+        \appendtomacro\captionline{: }% had ident, so need a colon between
+      \fi
+      %
+      % caption text.
+      \appendtomacro\captionline{\scanexp\thiscaption}%
+    \fi
+    %
+    % If we have anything to print, print it, with space before.
+    % Eventually this needs to become an \insert.
+    \ifx\captionline\empty \else
+      \vskip.5\parskip
+      \captionline
+      %
+      % Space below caption.
+      \vskip\parskip
+    \fi
+    %
+    % If have an xref label, write the list of floats info.  Do this
+    % after the caption, to avoid chance of it being a breakpoint.
+    \ifx\floatlabel\empty \else
+      % Write the text that goes in the lof to the aux file as
+      % \floatlabel-lof.  Besides \floatident, we include the short
+      % caption if specified, else the full caption if specified, else nothing.
+      {%
+        \requireauxfile
+        \atdummies
+        %
+        \ifx\thisshortcaption\empty
+          \def\gtemp{\thiscaption}%
+        \else
+          \def\gtemp{\thisshortcaption}%
+        \fi
+        \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+          \ifx\gtemp\empty \else : \gtemp \fi}}%
+      }%
+    \fi
+  \egroup  % end of \vtop
+  %
+  \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+  \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use.  Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+  \ifx#1\relax
+      % Haven't seen this figure type before.
+      \csname newcount\endcsname #1%
+      %
+      % Remember to reset this floatno at the next chap.
+      \expandafter\gdef\expandafter\resetallfloatnos
+        \expandafter{\resetallfloatnos #1=0 }%
+  \fi
+  \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value.  We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1".  We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref.  That is, the magic
+% \currentsection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string.  If so, #2 will be the
+% (safe) float type for this float.  We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+  \def\temp{#1}%
+  \def\iffloattype{#2}%
+  \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+  \def\floattype{#1}% floattype
+  {%
+    % the floattype might have accents or other special characters,
+    % but we need to use it in a control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safefloattype{\floattype}%
+  }%
+  %
+  % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+  \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+    \ifhavexrefs
+      % if the user said @listoffloats foo but never @float foo.
+      \message{\linenumber No `\safefloattype' floats to list.}%
+    \fi
+  \else
+    \begingroup
+      \leftskip=\tocindent  % indent these entries like a toc
+      \let\do=\listoffloatsdo
+      \csname floatlist\safefloattype\endcsname
+    \endgroup
+  \fi
+}
+
+% This is called on each entry in a list of floats.  We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file.  We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+  % Can't fully expand XR#1-lof because it can contain anything.  Just
+  % pass the control sequence.  On the other hand, XR#1-pg is just the
+  % page number, and we want to fully expand that so we can get a link
+  % in pdf output.
+  \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+  %
+  % use the same \entry macro we use to generate the TOC and index.
+  \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+  \writeentry
+}}
+
+
+\message{localization,}
+
+% For single-language documents, @documentlanguage is usually given very
+% early, just after @documentencoding.  Single argument is the language
+% (de) or locale (de_DE) abbreviation.
+%
+{
+  \catcode`\_ = \active
+  \globaldefs=1
+\parseargdef\documentlanguage{%
+  \tex % read txi-??.tex file in plain TeX.
+    % Read the file by the name they passed if it exists.
+    \let_ = \normalunderscore  % normal _ character for filename test
+    \openin 1 txi-#1.tex
+    \ifeof 1
+      \documentlanguagetrywithoutunderscore #1_\finish
+    \else
+      \globaldefs = 1  % everything in the txi-LL files needs to persist
+      \input txi-#1.tex
+    \fi
+    \closein 1
+  \endgroup % end raw TeX
+}
+%
+% If they passed de_DE, and txi-de_DE.tex doesn't exist,
+% try txi-de.tex.
+%
+\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{%
+  \openin 1 txi-#1.tex
+  \ifeof 1
+    \errhelp = \nolanghelp
+    \errmessage{Cannot read language file txi-#1.tex}%
+  \else
+    \globaldefs = 1  % everything in the txi-LL files needs to persist
+    \input txi-#1.tex
+  \fi
+  \closein 1
+}
+}% end of special _ catcode
+%
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty.  Maybe you need to install it?  Putting it in the current
+directory should work if nowhere else does.}
+
+% This macro is called from txi-??.tex files; the first argument is the
+% \language name to set (without the "\lang@" prefix), the second and
+% third args are \{left,right}hyphenmin.
+%
+% The language names to pass are determined when the format is built.
+% See the etex.log file created at that time, e.g.,
+% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log.
+%
+% With TeX Live 2008, etex now includes hyphenation patterns for all
+% available languages.  This means we can support hyphenation in
+% Texinfo, at least to some extent.  (This still doesn't solve the
+% accented characters problem.)
+%
+\catcode`@=11
+\def\txisetlanguage#1#2#3{%
+  % do not set the language if the name is undefined in the current TeX.
+  \expandafter\ifx\csname lang@#1\endcsname \relax
+    \message{no patterns for #1}%
+  \else
+    \global\language = \csname lang@#1\endcsname
+  \fi
+  % but there is no harm in adjusting the hyphenmin values regardless.
+  \global\lefthyphenmin = #2\relax
+  \global\righthyphenmin = #3\relax
+}
+
+% XeTeX and LuaTeX can handle Unicode natively.
+% Their default I/O uses UTF-8 sequences instead of a byte-wise operation.
+% Other TeX engines' I/O (pdfTeX, etc.) is byte-wise.
+%
+\newif\iftxinativeunicodecapable
+\newif\iftxiusebytewiseio
+
+\ifx\XeTeXrevision\thisisundefined
+  \ifx\luatexversion\thisisundefined
+    \txinativeunicodecapablefalse
+    \txiusebytewiseiotrue
+  \else
+    \txinativeunicodecapabletrue
+    \txiusebytewiseiofalse
+  \fi
+\else
+  \txinativeunicodecapabletrue
+  \txiusebytewiseiofalse
+\fi
+
+% Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex
+% for non-UTF-8 (byte-wise) encodings.
+%
+\def\setbytewiseio{%
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \XeTeXdefaultencoding "bytes"  % For subsequent files to be read
+    \XeTeXinputencoding "bytes"  % For document root file
+    % Unfortunately, there seems to be no corresponding XeTeX command for
+    % output encoding.  This is a problem for auxiliary index and TOC files.
+    % The only solution would be perhaps to write out @U{...} sequences in
+    % place of non-ASCII characters.
+  \fi
+
+  \ifx\luatexversion\thisisundefined
+  \else
+    \directlua{
+    local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
+    local function convert_char (char)
+      return utf8_char(byte(char))
+    end
+
+    local function convert_line (line)
+      return gsub(line, ".", convert_char)
+    end
+
+    callback.register("process_input_buffer", convert_line)
+
+    local function convert_line_out (line)
+      local line_out = ""
+      for c in string.utfvalues(line) do
+         line_out = line_out .. string.char(c)
+      end
+      return line_out
+    end
+
+    callback.register("process_output_buffer", convert_line_out)
+    }
+  \fi
+
+  \txiusebytewiseiotrue
+}
+
+
+% Helpers for encodings.
+% Set the catcode of characters 128 through 255 to the specified number.
+%
+\def\setnonasciicharscatcode#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \global\catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+\def\setnonasciicharscatcodenonglobal#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+% @documentencoding sets the definition of non-ASCII characters
+% according to the specified encoding.
+%
+\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz}
+\def\documentencodingzzz#1{%
+  %
+  % Encoding being declared for the document.
+  \def\declaredencoding{\csname #1.enc\endcsname}%
+  %
+  % Supported encodings: names converted to tokens in order to be able
+  % to compare them with \ifx.
+  \def\ascii{\csname US-ASCII.enc\endcsname}%
+  \def\latnine{\csname ISO-8859-15.enc\endcsname}%
+  \def\latone{\csname ISO-8859-1.enc\endcsname}%
+  \def\lattwo{\csname ISO-8859-2.enc\endcsname}%
+  \def\utfeight{\csname UTF-8.enc\endcsname}%
+  %
+  \ifx \declaredencoding \ascii
+     \asciichardefs
+  %
+  \else \ifx \declaredencoding \lattwo
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \lattwochardefs
+  %
+  \else \ifx \declaredencoding \latone
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latonechardefs
+  %
+  \else \ifx \declaredencoding \latnine
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latninechardefs
+  %
+  \else \ifx \declaredencoding \utfeight
+     \iftxinativeunicodecapable
+       % For native Unicode handling (XeTeX and LuaTeX)
+       \nativeunicodechardefs
+     \else
+       % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX)
+       \setnonasciicharscatcode\active
+       % since we already invoked \utfeightchardefs at the top level
+       % (below), do not re-invoke it, otherwise our check for duplicated
+       % definitions gets triggered.  Making non-ascii chars active is
+       % sufficient.
+     \fi
+  %
+  \else
+    \message{Ignoring unknown document encoding: #1.}%
+  %
+  \fi % utfeight
+  \fi % latnine
+  \fi % latone
+  \fi % lattwo
+  \fi % ascii
+  %
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \ifx \declaredencoding \utfeight
+    \else
+      \ifx \declaredencoding \ascii
+      \else
+        \message{Warning: XeTeX with non-UTF-8 encodings cannot handle %
+        non-ASCII characters in auxiliary files.}%
+      \fi
+    \fi
+  \fi
+}
+
+% emacs-page
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing, sorry: #1.}}
+
+% Take account of \c (plain) vs. \, (Texinfo) difference.
+\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi}
+
+% First, make active non-ASCII characters in order for them to be
+% correctly categorized when TeX reads the replacement text of
+% macros containing the character definitions.
+\setnonasciicharscatcode\active
+%
+
+\def\gdefchar#1#2{%
+\gdef#1{%
+   \ifpassthroughchars
+     \string#1%
+   \else
+     #2%
+   \fi
+}}
+
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\exclamdown}
+  \gdefchar^^a2{{\tcfont \char162}} % cent
+  \gdefchar^^a3{\pounds{}}
+  \gdefchar^^a4{{\tcfont \char164}} % currency
+  \gdefchar^^a5{{\tcfont \char165}} % yen
+  \gdefchar^^a6{{\tcfont \char166}} % broken bar
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\copyright{}}
+  \gdefchar^^aa{\ordf}
+  \gdefchar^^ab{\guillemetleft{}}
+  \gdefchar^^ac{\ensuremath\lnot}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\registeredsymbol{}}
+  \gdefchar^^af{\={}}
+  %
+  \gdefchar^^b0{\textdegree}
+  \gdefchar^^b1{$\pm$}
+  \gdefchar^^b2{$^2$}
+  \gdefchar^^b3{$^3$}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{$\mu$}
+  \gdefchar^^b6{\P}
+  \gdefchar^^b7{\ensuremath\cdot}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{$^1$}
+  \gdefchar^^ba{\ordm}
+  \gdefchar^^bb{\guillemetright{}}
+  \gdefchar^^bc{$1\over4$}
+  \gdefchar^^bd{$1\over2$}
+  \gdefchar^^be{$3\over4$}
+  \gdefchar^^bf{\questiondown}
+  %
+  \gdefchar^^c0{\`A}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\~A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\ringaccent A}
+  \gdefchar^^c6{\AE}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\`E}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\^E}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\`I}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\"I}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\~N}
+  \gdefchar^^d2{\`O}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\~O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\O}
+  \gdefchar^^d9{\`U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\^U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\TH}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\`a}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\~a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\ringaccent a}
+  \gdefchar^^e6{\ae}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\`e}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\^e}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\`{\dotless i}}
+  \gdefchar^^ed{\'{\dotless i}}
+  \gdefchar^^ee{\^{\dotless i}}
+  \gdefchar^^ef{\"{\dotless i}}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\~n}
+  \gdefchar^^f2{\`o}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\~o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\o}
+  \gdefchar^^f9{\`u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\^u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\th}
+  \gdefchar^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+  % Encoding is almost identical to Latin1.
+  \latonechardefs
+  %
+  \gdefchar^^a4{\euro{}}
+  \gdefchar^^a6{\v S}
+  \gdefchar^^a8{\v s}
+  \gdefchar^^b4{\v Z}
+  \gdefchar^^b8{\v z}
+  \gdefchar^^bc{\OE}
+  \gdefchar^^bd{\oe}
+  \gdefchar^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\ogonek{A}}
+  \gdefchar^^a2{\u{}}
+  \gdefchar^^a3{\L}
+  \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdefchar^^a5{\v L}
+  \gdefchar^^a6{\'S}
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\v S}
+  \gdefchar^^aa{\cedilla S}
+  \gdefchar^^ab{\v T}
+  \gdefchar^^ac{\'Z}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\v Z}
+  \gdefchar^^af{\dotaccent Z}
+  %
+  \gdefchar^^b0{\textdegree{}}
+  \gdefchar^^b1{\ogonek{a}}
+  \gdefchar^^b2{\ogonek{ }}
+  \gdefchar^^b3{\l}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{\v l}
+  \gdefchar^^b6{\'s}
+  \gdefchar^^b7{\v{}}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{\v s}
+  \gdefchar^^ba{\cedilla s}
+  \gdefchar^^bb{\v t}
+  \gdefchar^^bc{\'z}
+  \gdefchar^^bd{\H{}}
+  \gdefchar^^be{\v z}
+  \gdefchar^^bf{\dotaccent z}
+  %
+  \gdefchar^^c0{\'R}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\u A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\'L}
+  \gdefchar^^c6{\'C}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\v C}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\ogonek{E}}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\v E}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\v D}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\'N}
+  \gdefchar^^d2{\v N}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\H O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\v R}
+  \gdefchar^^d9{\ringaccent U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\H U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\cedilla T}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\'r}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\u a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\'l}
+  \gdefchar^^e6{\'c}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\v c}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\ogonek{e}}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\v e}
+  \gdefchar^^ed{\'{\dotless{i}}}
+  \gdefchar^^ee{\^{\dotless{i}}}
+  \gdefchar^^ef{\v d}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\'n}
+  \gdefchar^^f2{\v n}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\H o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\v r}
+  \gdefchar^^f9{\ringaccent u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\H u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\cedilla t}
+  \gdefchar^^ff{\dotaccent{}}
+}
+
+% UTF-8 character definitions.
+%
+% This code to support UTF-8 is based on LaTeX's utf8.def, with some
+% changes for Texinfo conventions.  It is included here under the GPL by
+% permission from Frank Mittelbach and the LaTeX team.
+%
+\newcount\countUTFx
+\newcount\countUTFy
+\newcount\countUTFz
+
+\gdef\UTFviiiTwoOctets#1#2{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\endcsname}
+%
+\gdef\UTFviiiThreeOctets#1#2#3{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname}
+%
+\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname}
+
+\gdef\UTFviiiDefined#1{%
+  \ifx #1\relax
+    \message{\linenumber Unicode char \string #1 not defined for Texinfo}%
+  \else
+    \expandafter #1%
+  \fi
+}
+
+% Give non-ASCII bytes the active definitions for processing UTF-8 sequences
+\begingroup
+  \catcode`\~13
+  \catcode`\$12
+  \catcode`\"12
+
+  % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp
+  % substituting ~ and $ with a character token of that value.
+  \def\UTFviiiLoop{%
+    \global\catcode\countUTFx\active
+    \uccode`\~\countUTFx
+    \uccode`\$\countUTFx
+    \uppercase\expandafter{\UTFviiiTmp}%
+    \advance\countUTFx by 1
+    \ifnum\countUTFx < \countUTFy
+      \expandafter\UTFviiiLoop
+    \fi}
+
+  % For bytes other than the first in a UTF-8 sequence.  Not expected to
+  % be expanded except when writing to auxiliary files.
+  \countUTFx = "80
+  \countUTFy = "C2
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "C2
+  \countUTFy = "E0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "E0
+  \countUTFy = "F0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "F0
+  \countUTFy = "F4
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiFourOctets\expandafter$\fi
+        }}%
+  \UTFviiiLoop
+\endgroup
+
+\def\globallet{\global\let} % save some \expandafter's below
+
+% @U{xxxx} to produce U+xxxx, if we support it.
+\def\U#1{%
+  \expandafter\ifx\csname uni:#1\endcsname \relax
+    \iftxinativeunicodecapable
+      % All Unicode characters can be used if native Unicode handling is
+      % active.  However, if the font does not have the glyph,
+      % letters are missing.
+      \begingroup
+        \uccode`\.="#1\relax
+        \uppercase{.}
+      \endgroup
+    \else
+      \errhelp = \EMsimple
+      \errmessage{Unicode character U+#1 not supported, sorry}%
+    \fi
+  \else
+    \csname uni:#1\endcsname
+  \fi
+}
+
+% These macros are used here to construct the name of a control
+% sequence to be defined.
+\def\UTFviiiTwoOctetsName#1#2{%
+  \csname u8:#1\string #2\endcsname}%
+\def\UTFviiiThreeOctetsName#1#2#3{%
+  \csname u8:#1\string #2\string #3\endcsname}%
+\def\UTFviiiFourOctetsName#1#2#3#4{%
+  \csname u8:#1\string #2\string #3\string #4\endcsname}%
+
+% For UTF-8 byte sequences (TeX, e-TeX and pdfTeX),
+% provide a definition macro to replace a Unicode character;
+% this gets used by the @U command
+%
+\begingroup
+  \catcode`\"=12
+  \catcode`\<=12
+  \catcode`\.=12
+  \catcode`\,=12
+  \catcode`\;=12
+  \catcode`\!=12
+  \catcode`\~=13
+  \gdef\DeclareUnicodeCharacterUTFviii#1#2{%
+    \countUTFz = "#1\relax
+    \begingroup
+      \parseXMLCharref
+
+      % Give \u8:... its definition.  The sequence of seven \expandafter's
+      % expands after the \gdef three times, e.g.
+      %
+      % 1.  \UTFviiTwoOctetsName B1 B2
+      % 2.  \csname u8:B1 \string B2 \endcsname
+      % 3.  \u8: B1 B2  (a single control sequence token)
+      %
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\gdef       \UTFviiiTmp{#2}%
+      %
+      \expandafter\ifx\csname uni:#1\endcsname \relax \else
+       \message{Internal error, already defined: #1}%
+      \fi
+      %
+      % define an additional control sequence for this code point.
+      \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp
+    \endgroup}
+  %
+  % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp
+  % to the corresponding UTF-8 sequence.
+  \gdef\parseXMLCharref{%
+    \ifnum\countUTFz < "A0\relax
+      \errhelp = \EMsimple
+      \errmessage{Cannot define Unicode char value < 00A0}%
+    \else\ifnum\countUTFz < "800\relax
+      \parseUTFviiiA,%
+      \parseUTFviiiB C\UTFviiiTwoOctetsName.,%
+    \else\ifnum\countUTFz < "10000\relax
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}%
+    \else
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiA!%
+      \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}%
+    \fi\fi\fi
+  }
+
+  % Extract a byte from the end of the UTF-8 representation of \countUTFx.
+  % It must be a non-initial byte in the sequence.
+  % Change \uccode of #1 for it to be used in \parseUTFviiiB as one
+  % of the bytes.
+  \gdef\parseUTFviiiA#1{%
+    \countUTFx = \countUTFz
+    \divide\countUTFz by 64
+    \countUTFy = \countUTFz  % Save to be the future value of \countUTFz.
+    \multiply\countUTFz by 64
+
+    % \countUTFz is now \countUTFx with the last 5 bits cleared.  Subtract
+    % in order to get the last five bits.
+    \advance\countUTFx by -\countUTFz
+
+    % Convert this to the byte in the UTF-8 sequence.
+    \advance\countUTFx by 128
+    \uccode `#1\countUTFx
+    \countUTFz = \countUTFy}
+
+  % Used to put a UTF-8 byte sequence into \UTFviiiTmp
+  % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8
+  %    sequence.
+  % #2 is one of the \UTFviii*OctetsName macros.
+  % #3 is always a full stop (.)
+  % #4 is a template for the other bytes in the sequence.  The values for these
+  %    bytes is substituted in here with \uppercase using the \uccode's.
+  \gdef\parseUTFviiiB#1#2#3#4{%
+    \advance\countUTFz by "#10\relax
+    \uccode `#3\countUTFz
+    \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro that sets a catcode to `other' non-globally
+%
+\def\DeclareUnicodeCharacterNativeOther#1#2{%
+  \catcode"#1=\other
+}
+
+% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
+% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
+% U+0080..U+00FF = 
https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)
+% U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A
+% U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B
+%
+% Many of our renditions are less than wonderful, and all the missing
+% characters are available somewhere.  Loading the necessary fonts
+% awaits user request.  We can't truly support Unicode without
+% reimplementing everything that's been done in LaTeX for many years,
+% plus probably using luatex or xetex, and who knows what else.
+% We won't be doing that here in this simple file.  But we can try to at
+% least make most of the characters not bomb out.
+%
+\def\unicodechardefs{%
+  \DeclareUnicodeCharacter{00A0}{\tie}%
+  \DeclareUnicodeCharacter{00A1}{\exclamdown}%
+  \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
+  \DeclareUnicodeCharacter{00A3}{\pounds{}}%
+  \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency
+  \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen
+  \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar
+  \DeclareUnicodeCharacter{00A7}{\S}%
+  \DeclareUnicodeCharacter{00A8}{\"{ }}%
+  \DeclareUnicodeCharacter{00A9}{\copyright{}}%
+  \DeclareUnicodeCharacter{00AA}{\ordf}%
+  \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}%
+  \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}%
+  \DeclareUnicodeCharacter{00AD}{\-}%
+  \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}%
+  \DeclareUnicodeCharacter{00AF}{\={ }}%
+  %
+  \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}%
+  \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}%
+  \DeclareUnicodeCharacter{00B2}{$^2$}%
+  \DeclareUnicodeCharacter{00B3}{$^3$}%
+  \DeclareUnicodeCharacter{00B4}{\'{ }}%
+  \DeclareUnicodeCharacter{00B5}{$\mu$}%
+  \DeclareUnicodeCharacter{00B6}{\P}%
+  \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{00B8}{\cedilla{ }}%
+  \DeclareUnicodeCharacter{00B9}{$^1$}%
+  \DeclareUnicodeCharacter{00BA}{\ordm}%
+  \DeclareUnicodeCharacter{00BB}{\guillemetright{}}%
+  \DeclareUnicodeCharacter{00BC}{$1\over4$}%
+  \DeclareUnicodeCharacter{00BD}{$1\over2$}%
+  \DeclareUnicodeCharacter{00BE}{$3\over4$}%
+  \DeclareUnicodeCharacter{00BF}{\questiondown}%
+  %
+  \DeclareUnicodeCharacter{00C0}{\`A}%
+  \DeclareUnicodeCharacter{00C1}{\'A}%
+  \DeclareUnicodeCharacter{00C2}{\^A}%
+  \DeclareUnicodeCharacter{00C3}{\~A}%
+  \DeclareUnicodeCharacter{00C4}{\"A}%
+  \DeclareUnicodeCharacter{00C5}{\AA}%
+  \DeclareUnicodeCharacter{00C6}{\AE}%
+  \DeclareUnicodeCharacter{00C7}{\cedilla{C}}%
+  \DeclareUnicodeCharacter{00C8}{\`E}%
+  \DeclareUnicodeCharacter{00C9}{\'E}%
+  \DeclareUnicodeCharacter{00CA}{\^E}%
+  \DeclareUnicodeCharacter{00CB}{\"E}%
+  \DeclareUnicodeCharacter{00CC}{\`I}%
+  \DeclareUnicodeCharacter{00CD}{\'I}%
+  \DeclareUnicodeCharacter{00CE}{\^I}%
+  \DeclareUnicodeCharacter{00CF}{\"I}%
+  %
+  \DeclareUnicodeCharacter{00D0}{\DH}%
+  \DeclareUnicodeCharacter{00D1}{\~N}%
+  \DeclareUnicodeCharacter{00D2}{\`O}%
+  \DeclareUnicodeCharacter{00D3}{\'O}%
+  \DeclareUnicodeCharacter{00D4}{\^O}%
+  \DeclareUnicodeCharacter{00D5}{\~O}%
+  \DeclareUnicodeCharacter{00D6}{\"O}%
+  \DeclareUnicodeCharacter{00D7}{\ensuremath\times}%
+  \DeclareUnicodeCharacter{00D8}{\O}%
+  \DeclareUnicodeCharacter{00D9}{\`U}%
+  \DeclareUnicodeCharacter{00DA}{\'U}%
+  \DeclareUnicodeCharacter{00DB}{\^U}%
+  \DeclareUnicodeCharacter{00DC}{\"U}%
+  \DeclareUnicodeCharacter{00DD}{\'Y}%
+  \DeclareUnicodeCharacter{00DE}{\TH}%
+  \DeclareUnicodeCharacter{00DF}{\ss}%
+  %
+  \DeclareUnicodeCharacter{00E0}{\`a}%
+  \DeclareUnicodeCharacter{00E1}{\'a}%
+  \DeclareUnicodeCharacter{00E2}{\^a}%
+  \DeclareUnicodeCharacter{00E3}{\~a}%
+  \DeclareUnicodeCharacter{00E4}{\"a}%
+  \DeclareUnicodeCharacter{00E5}{\aa}%
+  \DeclareUnicodeCharacter{00E6}{\ae}%
+  \DeclareUnicodeCharacter{00E7}{\cedilla{c}}%
+  \DeclareUnicodeCharacter{00E8}{\`e}%
+  \DeclareUnicodeCharacter{00E9}{\'e}%
+  \DeclareUnicodeCharacter{00EA}{\^e}%
+  \DeclareUnicodeCharacter{00EB}{\"e}%
+  \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}%
+  %
+  \DeclareUnicodeCharacter{00F0}{\dh}%
+  \DeclareUnicodeCharacter{00F1}{\~n}%
+  \DeclareUnicodeCharacter{00F2}{\`o}%
+  \DeclareUnicodeCharacter{00F3}{\'o}%
+  \DeclareUnicodeCharacter{00F4}{\^o}%
+  \DeclareUnicodeCharacter{00F5}{\~o}%
+  \DeclareUnicodeCharacter{00F6}{\"o}%
+  \DeclareUnicodeCharacter{00F7}{\ensuremath\div}%
+  \DeclareUnicodeCharacter{00F8}{\o}%
+  \DeclareUnicodeCharacter{00F9}{\`u}%
+  \DeclareUnicodeCharacter{00FA}{\'u}%
+  \DeclareUnicodeCharacter{00FB}{\^u}%
+  \DeclareUnicodeCharacter{00FC}{\"u}%
+  \DeclareUnicodeCharacter{00FD}{\'y}%
+  \DeclareUnicodeCharacter{00FE}{\th}%
+  \DeclareUnicodeCharacter{00FF}{\"y}%
+  %
+  \DeclareUnicodeCharacter{0100}{\=A}%
+  \DeclareUnicodeCharacter{0101}{\=a}%
+  \DeclareUnicodeCharacter{0102}{\u{A}}%
+  \DeclareUnicodeCharacter{0103}{\u{a}}%
+  \DeclareUnicodeCharacter{0104}{\ogonek{A}}%
+  \DeclareUnicodeCharacter{0105}{\ogonek{a}}%
+  \DeclareUnicodeCharacter{0106}{\'C}%
+  \DeclareUnicodeCharacter{0107}{\'c}%
+  \DeclareUnicodeCharacter{0108}{\^C}%
+  \DeclareUnicodeCharacter{0109}{\^c}%
+  \DeclareUnicodeCharacter{010A}{\dotaccent{C}}%
+  \DeclareUnicodeCharacter{010B}{\dotaccent{c}}%
+  \DeclareUnicodeCharacter{010C}{\v{C}}%
+  \DeclareUnicodeCharacter{010D}{\v{c}}%
+  \DeclareUnicodeCharacter{010E}{\v{D}}%
+  \DeclareUnicodeCharacter{010F}{d'}%
+  %
+  \DeclareUnicodeCharacter{0110}{\DH}%
+  \DeclareUnicodeCharacter{0111}{\dh}%
+  \DeclareUnicodeCharacter{0112}{\=E}%
+  \DeclareUnicodeCharacter{0113}{\=e}%
+  \DeclareUnicodeCharacter{0114}{\u{E}}%
+  \DeclareUnicodeCharacter{0115}{\u{e}}%
+  \DeclareUnicodeCharacter{0116}{\dotaccent{E}}%
+  \DeclareUnicodeCharacter{0117}{\dotaccent{e}}%
+  \DeclareUnicodeCharacter{0118}{\ogonek{E}}%
+  \DeclareUnicodeCharacter{0119}{\ogonek{e}}%
+  \DeclareUnicodeCharacter{011A}{\v{E}}%
+  \DeclareUnicodeCharacter{011B}{\v{e}}%
+  \DeclareUnicodeCharacter{011C}{\^G}%
+  \DeclareUnicodeCharacter{011D}{\^g}%
+  \DeclareUnicodeCharacter{011E}{\u{G}}%
+  \DeclareUnicodeCharacter{011F}{\u{g}}%
+  %
+  \DeclareUnicodeCharacter{0120}{\dotaccent{G}}%
+  \DeclareUnicodeCharacter{0121}{\dotaccent{g}}%
+  \DeclareUnicodeCharacter{0122}{\cedilla{G}}%
+  \DeclareUnicodeCharacter{0123}{\cedilla{g}}%
+  \DeclareUnicodeCharacter{0124}{\^H}%
+  \DeclareUnicodeCharacter{0125}{\^h}%
+  \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}%
+  \DeclareUnicodeCharacter{0128}{\~I}%
+  \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012A}{\=I}%
+  \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}%
+  \DeclareUnicodeCharacter{012C}{\u{I}}%
+  \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012E}{\ogonek{I}}%
+  \DeclareUnicodeCharacter{012F}{\ogonek{i}}%
+  %
+  \DeclareUnicodeCharacter{0130}{\dotaccent{I}}%
+  \DeclareUnicodeCharacter{0131}{\dotless{i}}%
+  \DeclareUnicodeCharacter{0132}{IJ}%
+  \DeclareUnicodeCharacter{0133}{ij}%
+  \DeclareUnicodeCharacter{0134}{\^J}%
+  \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}%
+  \DeclareUnicodeCharacter{0136}{\cedilla{K}}%
+  \DeclareUnicodeCharacter{0137}{\cedilla{k}}%
+  \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{0139}{\'L}%
+  \DeclareUnicodeCharacter{013A}{\'l}%
+  \DeclareUnicodeCharacter{013B}{\cedilla{L}}%
+  \DeclareUnicodeCharacter{013C}{\cedilla{l}}%
+  \DeclareUnicodeCharacter{013D}{L'}% should kern
+  \DeclareUnicodeCharacter{013E}{l'}% should kern
+  \DeclareUnicodeCharacter{013F}{L\U{00B7}}%
+  %
+  \DeclareUnicodeCharacter{0140}{l\U{00B7}}%
+  \DeclareUnicodeCharacter{0141}{\L}%
+  \DeclareUnicodeCharacter{0142}{\l}%
+  \DeclareUnicodeCharacter{0143}{\'N}%
+  \DeclareUnicodeCharacter{0144}{\'n}%
+  \DeclareUnicodeCharacter{0145}{\cedilla{N}}%
+  \DeclareUnicodeCharacter{0146}{\cedilla{n}}%
+  \DeclareUnicodeCharacter{0147}{\v{N}}%
+  \DeclareUnicodeCharacter{0148}{\v{n}}%
+  \DeclareUnicodeCharacter{0149}{'n}%
+  \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}%
+  \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}%
+  \DeclareUnicodeCharacter{014C}{\=O}%
+  \DeclareUnicodeCharacter{014D}{\=o}%
+  \DeclareUnicodeCharacter{014E}{\u{O}}%
+  \DeclareUnicodeCharacter{014F}{\u{o}}%
+  %
+  \DeclareUnicodeCharacter{0150}{\H{O}}%
+  \DeclareUnicodeCharacter{0151}{\H{o}}%
+  \DeclareUnicodeCharacter{0152}{\OE}%
+  \DeclareUnicodeCharacter{0153}{\oe}%
+  \DeclareUnicodeCharacter{0154}{\'R}%
+  \DeclareUnicodeCharacter{0155}{\'r}%
+  \DeclareUnicodeCharacter{0156}{\cedilla{R}}%
+  \DeclareUnicodeCharacter{0157}{\cedilla{r}}%
+  \DeclareUnicodeCharacter{0158}{\v{R}}%
+  \DeclareUnicodeCharacter{0159}{\v{r}}%
+  \DeclareUnicodeCharacter{015A}{\'S}%
+  \DeclareUnicodeCharacter{015B}{\'s}%
+  \DeclareUnicodeCharacter{015C}{\^S}%
+  \DeclareUnicodeCharacter{015D}{\^s}%
+  \DeclareUnicodeCharacter{015E}{\cedilla{S}}%
+  \DeclareUnicodeCharacter{015F}{\cedilla{s}}%
+  %
+  \DeclareUnicodeCharacter{0160}{\v{S}}%
+  \DeclareUnicodeCharacter{0161}{\v{s}}%
+  \DeclareUnicodeCharacter{0162}{\cedilla{T}}%
+  \DeclareUnicodeCharacter{0163}{\cedilla{t}}%
+  \DeclareUnicodeCharacter{0164}{\v{T}}%
+  \DeclareUnicodeCharacter{0165}{\v{t}}%
+  \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}%
+  \DeclareUnicodeCharacter{0168}{\~U}%
+  \DeclareUnicodeCharacter{0169}{\~u}%
+  \DeclareUnicodeCharacter{016A}{\=U}%
+  \DeclareUnicodeCharacter{016B}{\=u}%
+  \DeclareUnicodeCharacter{016C}{\u{U}}%
+  \DeclareUnicodeCharacter{016D}{\u{u}}%
+  \DeclareUnicodeCharacter{016E}{\ringaccent{U}}%
+  \DeclareUnicodeCharacter{016F}{\ringaccent{u}}%
+  %
+  \DeclareUnicodeCharacter{0170}{\H{U}}%
+  \DeclareUnicodeCharacter{0171}{\H{u}}%
+  \DeclareUnicodeCharacter{0172}{\ogonek{U}}%
+  \DeclareUnicodeCharacter{0173}{\ogonek{u}}%
+  \DeclareUnicodeCharacter{0174}{\^W}%
+  \DeclareUnicodeCharacter{0175}{\^w}%
+  \DeclareUnicodeCharacter{0176}{\^Y}%
+  \DeclareUnicodeCharacter{0177}{\^y}%
+  \DeclareUnicodeCharacter{0178}{\"Y}%
+  \DeclareUnicodeCharacter{0179}{\'Z}%
+  \DeclareUnicodeCharacter{017A}{\'z}%
+  \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}%
+  \DeclareUnicodeCharacter{017C}{\dotaccent{z}}%
+  \DeclareUnicodeCharacter{017D}{\v{Z}}%
+  \DeclareUnicodeCharacter{017E}{\v{z}}%
+  \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}%
+  %
+  \DeclareUnicodeCharacter{01C4}{D\v{Z}}%
+  \DeclareUnicodeCharacter{01C5}{D\v{z}}%
+  \DeclareUnicodeCharacter{01C6}{d\v{z}}%
+  \DeclareUnicodeCharacter{01C7}{LJ}%
+  \DeclareUnicodeCharacter{01C8}{Lj}%
+  \DeclareUnicodeCharacter{01C9}{lj}%
+  \DeclareUnicodeCharacter{01CA}{NJ}%
+  \DeclareUnicodeCharacter{01CB}{Nj}%
+  \DeclareUnicodeCharacter{01CC}{nj}%
+  \DeclareUnicodeCharacter{01CD}{\v{A}}%
+  \DeclareUnicodeCharacter{01CE}{\v{a}}%
+  \DeclareUnicodeCharacter{01CF}{\v{I}}%
+  %
+  \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}%
+  \DeclareUnicodeCharacter{01D1}{\v{O}}%
+  \DeclareUnicodeCharacter{01D2}{\v{o}}%
+  \DeclareUnicodeCharacter{01D3}{\v{U}}%
+  \DeclareUnicodeCharacter{01D4}{\v{u}}%
+  %
+  \DeclareUnicodeCharacter{01E2}{\={\AE}}%
+  \DeclareUnicodeCharacter{01E3}{\={\ae}}%
+  \DeclareUnicodeCharacter{01E6}{\v{G}}%
+  \DeclareUnicodeCharacter{01E7}{\v{g}}%
+  \DeclareUnicodeCharacter{01E8}{\v{K}}%
+  \DeclareUnicodeCharacter{01E9}{\v{k}}%
+  %
+  \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}%
+  \DeclareUnicodeCharacter{01F1}{DZ}%
+  \DeclareUnicodeCharacter{01F2}{Dz}%
+  \DeclareUnicodeCharacter{01F3}{dz}%
+  \DeclareUnicodeCharacter{01F4}{\'G}%
+  \DeclareUnicodeCharacter{01F5}{\'g}%
+  \DeclareUnicodeCharacter{01F8}{\`N}%
+  \DeclareUnicodeCharacter{01F9}{\`n}%
+  \DeclareUnicodeCharacter{01FC}{\'{\AE}}%
+  \DeclareUnicodeCharacter{01FD}{\'{\ae}}%
+  \DeclareUnicodeCharacter{01FE}{\'{\O}}%
+  \DeclareUnicodeCharacter{01FF}{\'{\o}}%
+  %
+  \DeclareUnicodeCharacter{021E}{\v{H}}%
+  \DeclareUnicodeCharacter{021F}{\v{h}}%
+  %
+  \DeclareUnicodeCharacter{0226}{\dotaccent{A}}%
+  \DeclareUnicodeCharacter{0227}{\dotaccent{a}}%
+  \DeclareUnicodeCharacter{0228}{\cedilla{E}}%
+  \DeclareUnicodeCharacter{0229}{\cedilla{e}}%
+  \DeclareUnicodeCharacter{022E}{\dotaccent{O}}%
+  \DeclareUnicodeCharacter{022F}{\dotaccent{o}}%
+  %
+  \DeclareUnicodeCharacter{0232}{\=Y}%
+  \DeclareUnicodeCharacter{0233}{\=y}%
+  \DeclareUnicodeCharacter{0237}{\dotless{j}}%
+  %
+  \DeclareUnicodeCharacter{02DB}{\ogonek{ }}%
+  %
+  % Greek letters upper case
+  \DeclareUnicodeCharacter{0391}{{\it A}}%
+  \DeclareUnicodeCharacter{0392}{{\it B}}%
+  \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}%
+  \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}%
+  \DeclareUnicodeCharacter{0395}{{\it E}}%
+  \DeclareUnicodeCharacter{0396}{{\it Z}}%
+  \DeclareUnicodeCharacter{0397}{{\it H}}%
+  \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}%
+  \DeclareUnicodeCharacter{0399}{{\it I}}%
+  \DeclareUnicodeCharacter{039A}{{\it K}}%
+  \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}%
+  \DeclareUnicodeCharacter{039C}{{\it M}}%
+  \DeclareUnicodeCharacter{039D}{{\it N}}%
+  \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}%
+  \DeclareUnicodeCharacter{039F}{{\it O}}%
+  \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}%
+  \DeclareUnicodeCharacter{03A1}{{\it P}}%
+  %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma
+  \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}%
+  \DeclareUnicodeCharacter{03A4}{{\it T}}%
+  \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}%
+  \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}%
+  \DeclareUnicodeCharacter{03A7}{{\it X}}%
+  \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}%
+  \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}%
+  %
+  % Vowels with accents
+  \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}%
+  \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}%
+  \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}%
+  \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}%
+  \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}%
+  \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}%
+  %
+  % Standalone accent
+  \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}%
+  %
+  % Greek letters lower case
+  \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}%
+  \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}%
+  \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}%
+  \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}%
+  \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}%
+  \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}%
+  \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}%
+  \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}%
+  \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}%
+  \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}%
+  \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}%
+  \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}%
+  \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}%
+  \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron
+  \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}%
+  \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}%
+  \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}%
+  \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}%
+  \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}%
+  \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}%
+  \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}%
+  \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}%
+  \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}%
+  \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}%
+  %
+  % More Greek vowels with accents
+  \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}%
+  \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}%
+  \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}%
+  \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}%
+  \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}%
+  %
+  % Variant Greek letters
+  \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}%
+  \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}%
+  \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}%
+  %
+  \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}%
+  \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}%
+  \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}%
+  \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}%
+  \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}%
+  \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}%
+  \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}%
+  \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}%
+  \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}%
+  \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}%
+  \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}%
+  \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}%
+  %
+  \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}%
+  \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}%
+  %
+  \DeclareUnicodeCharacter{1E20}{\=G}%
+  \DeclareUnicodeCharacter{1E21}{\=g}%
+  \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}%
+  \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}%
+  \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}%
+  \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}%
+  \DeclareUnicodeCharacter{1E26}{\"H}%
+  \DeclareUnicodeCharacter{1E27}{\"h}%
+  %
+  \DeclareUnicodeCharacter{1E30}{\'K}%
+  \DeclareUnicodeCharacter{1E31}{\'k}%
+  \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}%
+  \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}%
+  \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}%
+  \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}%
+  \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}%
+  \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}%
+  \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}%
+  \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}%
+  \DeclareUnicodeCharacter{1E3E}{\'M}%
+  \DeclareUnicodeCharacter{1E3F}{\'m}%
+  %
+  \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}%
+  \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}%
+  \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}%
+  \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}%
+  \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}%
+  \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}%
+  \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}%
+  \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}%
+  \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}%
+  \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}%
+  %
+  \DeclareUnicodeCharacter{1E54}{\'P}%
+  \DeclareUnicodeCharacter{1E55}{\'p}%
+  \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}%
+  \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}%
+  \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}%
+  \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}%
+  \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}%
+  \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}%
+  \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}%
+  \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}%
+  %
+  \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}%
+  \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}%
+  \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}%
+  \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}%
+  \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}%
+  \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}%
+  \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}%
+  \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}%
+  \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}%
+  \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}%
+  %
+  \DeclareUnicodeCharacter{1E7C}{\~V}%
+  \DeclareUnicodeCharacter{1E7D}{\~v}%
+  \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}%
+  \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}%
+  %
+  \DeclareUnicodeCharacter{1E80}{\`W}%
+  \DeclareUnicodeCharacter{1E81}{\`w}%
+  \DeclareUnicodeCharacter{1E82}{\'W}%
+  \DeclareUnicodeCharacter{1E83}{\'w}%
+  \DeclareUnicodeCharacter{1E84}{\"W}%
+  \DeclareUnicodeCharacter{1E85}{\"w}%
+  \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}%
+  \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}%
+  \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}%
+  \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}%
+  \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}%
+  \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}%
+  \DeclareUnicodeCharacter{1E8C}{\"X}%
+  \DeclareUnicodeCharacter{1E8D}{\"x}%
+  \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}%
+  \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}%
+  %
+  \DeclareUnicodeCharacter{1E90}{\^Z}%
+  \DeclareUnicodeCharacter{1E91}{\^z}%
+  \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}%
+  \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}%
+  \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}%
+  \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}%
+  \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}%
+  \DeclareUnicodeCharacter{1E97}{\"t}%
+  \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}%
+  \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}%
+  %
+  \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}%
+  \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}%
+  %
+  \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}%
+  \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}%
+  \DeclareUnicodeCharacter{1EBC}{\~E}%
+  \DeclareUnicodeCharacter{1EBD}{\~e}%
+  %
+  \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}%
+  \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}%
+  \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}%
+  \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}%
+  %
+  \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}%
+  \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}%
+  %
+  \DeclareUnicodeCharacter{1EF2}{\`Y}%
+  \DeclareUnicodeCharacter{1EF3}{\`y}%
+  \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}%
+  %
+  \DeclareUnicodeCharacter{1EF8}{\~Y}%
+  \DeclareUnicodeCharacter{1EF9}{\~y}%
+  %
+  % Punctuation
+  \DeclareUnicodeCharacter{2013}{--}%
+  \DeclareUnicodeCharacter{2014}{---}%
+  \DeclareUnicodeCharacter{2018}{\quoteleft{}}%
+  \DeclareUnicodeCharacter{2019}{\quoteright{}}%
+  \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}%
+  \DeclareUnicodeCharacter{201C}{\quotedblleft{}}%
+  \DeclareUnicodeCharacter{201D}{\quotedblright{}}%
+  \DeclareUnicodeCharacter{201E}{\quotedblbase{}}%
+  \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}%
+  \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}%
+  \DeclareUnicodeCharacter{2022}{\bullet{}}%
+  \DeclareUnicodeCharacter{202F}{\thinspace}%
+  \DeclareUnicodeCharacter{2026}{\dots{}}%
+  \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}%
+  \DeclareUnicodeCharacter{203A}{\guilsinglright{}}%
+  %
+  \DeclareUnicodeCharacter{20AC}{\euro{}}%
+  %
+  \DeclareUnicodeCharacter{2192}{\expansion{}}%
+  \DeclareUnicodeCharacter{21D2}{\result{}}%
+  %
+  % Mathematical symbols
+  \DeclareUnicodeCharacter{2200}{\ensuremath\forall}%
+  \DeclareUnicodeCharacter{2203}{\ensuremath\exists}%
+  \DeclareUnicodeCharacter{2208}{\ensuremath\in}%
+  \DeclareUnicodeCharacter{2212}{\minus{}}%
+  \DeclareUnicodeCharacter{2217}{\ast}%
+  \DeclareUnicodeCharacter{221E}{\ensuremath\infty}%
+  \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}%
+  \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}%
+  \DeclareUnicodeCharacter{2229}{\ensuremath\cap}%
+  \DeclareUnicodeCharacter{2261}{\equiv{}}%
+  \DeclareUnicodeCharacter{2264}{\ensuremath\leq}%
+  \DeclareUnicodeCharacter{2265}{\ensuremath\geq}%
+  \DeclareUnicodeCharacter{2282}{\ensuremath\subset}%
+  \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}%
+  %
+  \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}%
+  \DeclareUnicodeCharacter{2032}{\ensuremath\prime}%
+  \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}%
+  \DeclareUnicodeCharacter{2111}{\ensuremath\Im}%
+  \DeclareUnicodeCharacter{2113}{\ensuremath\ell}%
+  \DeclareUnicodeCharacter{2118}{\ensuremath\wp}%
+  \DeclareUnicodeCharacter{211C}{\ensuremath\Re}%
+  \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}%
+  \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}%
+  \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}%
+  \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}%
+  \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}%
+  \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}%
+  \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}%
+  \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}%
+  \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}%
+  \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}%
+  \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}%
+  \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}%
+  \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}%
+  \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}%
+  \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}%
+  \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}%
+  \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}%
+  \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}%
+  \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}%
+  \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}%
+  \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}%
+  \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}%
+  \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}%
+  \DeclareUnicodeCharacter{2202}{\ensuremath\partial}%
+  \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}%
+  \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}%
+  \DeclareUnicodeCharacter{2209}{\ensuremath\notin}%
+  \DeclareUnicodeCharacter{220B}{\ensuremath\owns}%
+  \DeclareUnicodeCharacter{220F}{\ensuremath\prod}%
+  \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}%
+  \DeclareUnicodeCharacter{2211}{\ensuremath\sum}%
+  \DeclareUnicodeCharacter{2213}{\ensuremath\mp}%
+  \DeclareUnicodeCharacter{2218}{\ensuremath\circ}%
+  \DeclareUnicodeCharacter{221A}{\ensuremath\surd}%
+  \DeclareUnicodeCharacter{221D}{\ensuremath\propto}%
+  \DeclareUnicodeCharacter{2220}{\ensuremath\angle}%
+  \DeclareUnicodeCharacter{2223}{\ensuremath\mid}%
+  \DeclareUnicodeCharacter{2228}{\ensuremath\vee}%
+  \DeclareUnicodeCharacter{222A}{\ensuremath\cup}%
+  \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}%
+  \DeclareUnicodeCharacter{222E}{\ensuremath\oint}%
+  \DeclareUnicodeCharacter{223C}{\ensuremath\sim}%
+  \DeclareUnicodeCharacter{2240}{\ensuremath\wr}%
+  \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}%
+  \DeclareUnicodeCharacter{2245}{\ensuremath\cong}%
+  \DeclareUnicodeCharacter{2248}{\ensuremath\approx}%
+  \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}%
+  \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}%
+  \DeclareUnicodeCharacter{2260}{\ensuremath\neq}%
+  \DeclareUnicodeCharacter{226A}{\ensuremath\ll}%
+  \DeclareUnicodeCharacter{226B}{\ensuremath\gg}%
+  \DeclareUnicodeCharacter{227A}{\ensuremath\prec}%
+  \DeclareUnicodeCharacter{227B}{\ensuremath\succ}%
+  \DeclareUnicodeCharacter{2283}{\ensuremath\supset}%
+  \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}%
+  \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}%
+  \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}%
+  \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}%
+  \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}%
+  \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}%
+  \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}%
+  \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}%
+  \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}%
+  \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}%
+  \DeclareUnicodeCharacter{2299}{\ensuremath\odot}%
+  \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}%
+  \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}%
+  \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}%
+  \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}%
+  \DeclareUnicodeCharacter{22A8}{\ensuremath\models}%
+  \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}%
+  \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}%
+  \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}%
+  \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}%
+  \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{22C6}{\ensuremath\star}%
+  \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}%
+  \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}%
+  \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}%
+  \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}%
+  \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}%
+  \DeclareUnicodeCharacter{2322}{\ensuremath\frown}%
+  \DeclareUnicodeCharacter{2323}{\ensuremath\smile}%
+  %
+  \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}%
+  \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}%
+  \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}%
+  \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}%
+  \DeclareUnicodeCharacter{25C7}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}%
+  \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}%
+  \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}%
+  \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}%
+  \DeclareUnicodeCharacter{266D}{\ensuremath\flat}%
+  \DeclareUnicodeCharacter{266E}{\ensuremath\natural}%
+  \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}%
+  \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}%
+  \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}%
+  \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}%
+  \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}%
+  \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}%
+  \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}%
+  \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}%
+  \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}%
+  \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}%
+  \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}%
+  \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}%
+  \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}%
+  \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}%
+  \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}%
+  \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}%
+  \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}%
+  \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}%
+  %
+  \global\mathchardef\checkmark="1370% actually the square root sign
+  \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}%
+}% end of \unicodechardefs
+
+% UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command)
+% It makes the setting that replace UTF-8 byte sequence.
+\def\utfeightchardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii
+  \unicodechardefs
+}
+
+% Whether the active definitions of non-ASCII characters expand to
+% non-active tokens with the same character code.  This is used to
+% write characters literally, instead of using active definitions for
+% printing the correct glyphs.
+\newif\ifpassthroughchars
+\passthroughcharsfalse
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro to replace/pass-through a Unicode character
+%
+\def\DeclareUnicodeCharacterNative#1#2{%
+  \catcode"#1=\active
+  \def\dodeclareunicodecharacternative##1##2##3{%
+    \begingroup
+      \uccode`\~="##2\relax
+      \uppercase{\gdef~}{%
+        \ifpassthroughchars
+          ##1%
+        \else
+          ##3%
+        \fi
+      }
+    \endgroup
+  }
+  \begingroup
+    \uccode`\.="#1\relax
+    \uppercase{\def\UTFNativeTmp{.}}%
+    \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
+  \endgroup
+}
+
+% Native Unicode handling (XeTeX and LuaTeX) character replacing definition.
+% It activates the setting that replaces Unicode characters.
+\def\nativeunicodechardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative
+  \unicodechardefs
+}
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% make the character token expand
+% to the sequences given in \unicodechardefs for printing.
+\def\DeclareUnicodeCharacterNativeAtU#1#2{%
+  \def\UTFAtUTmp{#2}
+  \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp
+}
+
+% @U command definitions for native Unicode handling (XeTeX and LuaTeX).
+\def\nativeunicodechardefsatu{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU
+  \unicodechardefs
+}
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+   \relax
+}
+
+% Define all Unicode characters we know about.  This makes UTF-8 the default
+% input encoding and allows @U to work.
+\iftxinativeunicodecapable
+  \nativeunicodechardefsatu
+\else
+  \utfeightchardefs
+\fi
+
+\message{formatting,}
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = .15\hsize
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading.  The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \txipageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \txipagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \ifpdf
+    \pdfpageheight #7\relax
+    \pdfpagewidth #8\relax
+    % if we don't reset these, they will remain at "1 true in" of
+    % whatever layout pdftex was dumped with.
+    \pdfhorigin = 1 true in
+    \pdfvorigin = 1 true in
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      \special{papersize=#8,#7}%
+    \else
+      \pdfpageheight #7\relax
+      \pdfpagewidth #8\relax
+      % XeTeX does not have \pdfhorigin and \pdfvorigin.
+    \fi
+  \fi
+  %
+  \setleading{\textleading}
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{607.2pt}{6in}% that's 46 lines
+                    {\voffset}{.25in}%
+                    {\bindingoffset}{36pt}%
+                    {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.25 trim size.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.5in}{5in}%
+                    {-.2in}{0in}%
+                    {\bindingoffset}{16pt}%
+                    {9.25in}{7in}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = .5cm
+}}
+
+% Use @smallerbook to reset parameters for 6x9 trim size.
+% (Just testing, parameters still in flux.)
+\def\smallerbook{{\globaldefs = 1
+  \parskip = 1.5pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.4in}{4.8in}%
+                    {-.2in}{-.4in}%
+                    {0pt}{14pt}%
+                    {9in}{6in}%
+  %
+  \lispnarrowing = 0.25in
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = .4cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % Double-side printing via postscript on Laserjet 4050
+  % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+  % To change the settings for a different printer or situation, adjust
+  % \normaloffset until the front-side and back-side texts align.  Then
+  % do the same for \bindingoffset.  You can set these for testing in
+  % your texinfo source file like this:
+  % @tex
+  % \global\normaloffset = -6mm
+  % \global\bindingoffset = 10mm
+  % @end tex
+  \internalpagesizes{673.2pt}{160mm}% that's 51 lines
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{44pt}%
+                    {297mm}{210mm}%
+  %
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+  \parskip = 2pt plus 1pt minus 0.1pt
+  \textleading = 12.5pt
+  %
+  \internalpagesizes{160mm}{120mm}%
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{8pt}%
+                    {210mm}{148mm}%
+  %
+  \lispnarrowing = 0.2in
+  \tolerance = 800
+  \contentsrightmargin = 0pt
+  \defbodyindent = 2mm
+  \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}%
+                    {\voffset}{4.6mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  %
+  % Must explicitly reset to 0 because we call \afourpaper.
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{241mm}{165mm}%
+                    {\voffset}{-2.95mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  \globaldefs = 0
+}}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{\textleading}%
+  %
+  \dimen0 = #1\relax
+  \advance\dimen0 by \voffset
+  \advance\dimen0 by 1in % reference point for DVI is 1 inch from top of page
+  %
+  \dimen2 = \hsize
+  \advance\dimen2 by \normaloffset
+  \advance\dimen2 by 1in % reference point is 1 inch from left edge of page
+  %
+  \internalpagesizes{#1}{\hsize}%
+                    {\voffset}{\normaloffset}%
+                    {\bindingoffset}{44pt}%
+                    {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+% Default value of \hfuzz, for suppressing warnings about overfull hboxes.
+\hfuzz = 1pt
+
+
+\message{and turning on texinfo input format.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font.  Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts.  But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Set catcodes for Texinfo file
+
+% Active characters for printing the wanted glyph.
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+%
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active \def\activetilde{{\tt\char126}} \let~ = \activetilde
+\chardef\hatchar=`\^
+\catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+\let\realunder=_
+
+\catcode`\|=\active \def|{{\tt\char124}}
+
+\chardef \less=`\<
+\catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless
+\chardef \gtr=`\>
+\catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr
+\catcode`\+=\active \def+{{\tt \char 43}}
+\catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+\catcode`\-=\active \let-=\normaldash
+
+
+% used for headline/footline in the output routine, in case the page
+% breaks in the middle of an @tex block.
+\def\texinfochars{%
+  \let< = \activeless
+  \let> = \activegtr
+  \let~ = \activetilde
+  \let^ = \activehat
+  \markupsetuplqdefault \markupsetuprqdefault
+  \let\b = \strong
+  \let\i = \smartitalic
+  % in principle, all other definitions in \tex have to be undone too.
+}
+
+% Used sometimes to turn off (effectively) the active characters even after
+% parsing them.
+\def\turnoffactive{%
+  \normalturnoffactive
+  \otherbackslash
+}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+
+% \realbackslash is an actual character `\' with catcode other.
+{\catcode`\\=\other @gdef@realbackslash{\}}
+
+% In Texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active  % @ for escape char from now on.
+
+% Print a typewriter backslash.  For math mode, we can't simply use
+% \backslashcurfont: the story here is that in math mode, the \char
+% of \backslashcurfont ends up printing the roman \ from the math symbol
+% font (because \char in math mode uses the \mathcode, and plain.tex
+% sets \mathcode`\\="026E).  Hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C).  We can't use " for the
+% usual hex value because it has already been made active.
+
+@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents.
+
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+{@catcode`- = @active
+ @gdef@normalturnoffactive{%
+   @passthroughcharstrue
+   @let-=@normaldash
+   @let"=@normaldoublequote
+   @let$=@normaldollar %$ font-lock fix
+   @let+=@normalplus
+   @let<=@normalless
+   @let>=@normalgreater
+   @let^=@normalcaret
+   @let_=@normalunderscore
+   @let|=@normalverticalbar
+   @let~=@normaltilde
+   @let\=@ttbackslash
+   @markupsetuplqdefault
+   @markupsetuprqdefault
+   @unsepspaces
+ }
+}
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have @fixbackslash turn them back on.
+@catcode`+=@other @catcode`@_=@other
+
+% \enablebackslashhack - allow file to begin `\input texinfo'
+%
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+% If the file did not have a `\input texinfo', then it is turned off after
+% the first line; otherwise the first `\' in the file would cause an error.
+% This is used on the very last line of this file, texinfo.tex.
+% We also use @c to call @fixbackslash, in case ends of lines are hidden.
+{
+@catcode`@^=7
+@catcode`@^^M=13@gdef@enablebackslashhack{%
+  @global@let\ = @eatinput%
+  @catcode`@^^M=13%
+  @def@c{@fixbackslash@c}%
+  % Definition for the newline at the end of this file.
+  @def ^^M{@let^^M@secondlinenl}%
+  % Definition for a newline in the main Texinfo file.
+  @gdef @secondlinenl{@fixbackslash}%
+  % In case the first line has a whole-line command on it
+  @let@originalparsearg@parsearg
+  @def@parsearg{@fixbackslash@originalparsearg}
+}}
+
+{@catcode`@^=7 @catcode`@^^M=13%
+@gdef@eatinput input texinfo#1^^M{@fixbackslash}}
+
+% Emergency active definition of newline, in case an active newline token
+% appears by mistake.
+{@catcode`@^=7 @catcode13=13%
+@gdef@enableemergencynewline{%
+  @gdef^^M{%
+    @par%
+    %<warning: active newline>@par%
+}}}
+
+
+@gdef@fixbackslash{%
+  @ifx\@eatinput @let\ = @ttbackslash @fi
+  @catcode13=5 % regular end of line
+  @enableemergencynewline
+  @let@c=@comment
+  @let@parsearg@originalparsearg
+  % Also turn back on active characters that might appear in the input
+  % file name, in case not using a pre-dumped format.
+  @catcode`+=@active
+  @catcode`@_=@active
+  %
+  % If texinfo.cnf is present on the system, read it.
+  % Useful for site-wide @afourpaper, etc.  This macro, @fixbackslash, gets
+  % called at the beginning of every Texinfo file.  Not opening texinfo.cnf
+  % directly in this file, texinfo.tex, makes it possible to make a format
+  % file for Texinfo.
+  %
+  @openin 1 texinfo.cnf
+  @ifeof 1 @else @input texinfo.cnf @fi
+  @closein 1
+}
+
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}.  If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@markupsetuplqdefault
+@markupsetuprqdefault
+
+@c Local variables:
+@c eval: (add-hook 'before-save-hook 'time-stamp)
+@c page-delimiter: "^\\\\message\\|emacs-page"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@enablebackslashhack



reply via email to

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