summaryrefslogtreecommitdiffstats
path: root/third_party/python/jinxed
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/python/jinxed
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/jinxed')
-rw-r--r--third_party/python/jinxed/jinxed-1.2.0.dist-info/LICENSE373
-rw-r--r--third_party/python/jinxed/jinxed-1.2.0.dist-info/METADATA112
-rw-r--r--third_party/python/jinxed/jinxed-1.2.0.dist-info/RECORD18
-rw-r--r--third_party/python/jinxed/jinxed-1.2.0.dist-info/WHEEL6
-rw-r--r--third_party/python/jinxed/jinxed-1.2.0.dist-info/top_level.txt1
-rw-r--r--third_party/python/jinxed/jinxed/__init__.py39
-rw-r--r--third_party/python/jinxed/jinxed/_keys.py164
-rw-r--r--third_party/python/jinxed/jinxed/_terminal.py123
-rw-r--r--third_party/python/jinxed/jinxed/_tparm.py291
-rw-r--r--third_party/python/jinxed/jinxed/_util.py52
-rw-r--r--third_party/python/jinxed/jinxed/has_key.py158
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/__init__.py87
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/ansicon.py158
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/vtwin10.py68
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/xterm.py482
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/xterm_256color.py28
-rw-r--r--third_party/python/jinxed/jinxed/terminfo/xterm_256colors.py28
-rw-r--r--third_party/python/jinxed/jinxed/win32.py352
18 files changed, 2540 insertions, 0 deletions
diff --git a/third_party/python/jinxed/jinxed-1.2.0.dist-info/LICENSE b/third_party/python/jinxed/jinxed-1.2.0.dist-info/LICENSE
new file mode 100644
index 0000000000..a612ad9813
--- /dev/null
+++ b/third_party/python/jinxed/jinxed-1.2.0.dist-info/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/third_party/python/jinxed/jinxed-1.2.0.dist-info/METADATA b/third_party/python/jinxed/jinxed-1.2.0.dist-info/METADATA
new file mode 100644
index 0000000000..ae98a1b6fb
--- /dev/null
+++ b/third_party/python/jinxed/jinxed-1.2.0.dist-info/METADATA
@@ -0,0 +1,112 @@
+Metadata-Version: 2.1
+Name: jinxed
+Version: 1.2.0
+Summary: Jinxed Terminal Library
+Home-page: https://github.com/Rockhopper-Technologies/jinxed
+Author: Avram Lubkin
+Author-email: avylove@rockhopper.net
+Maintainer: Avram Lubkin
+Maintainer-email: avylove@rockhopper.net
+License: MPLv2.0
+Keywords: terminal console blessed curses
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Terminals
+License-File: LICENSE
+Requires-Dist: ansicon ; platform_system == "Windows"
+
+.. start-badges
+
+| |docs| |appveyor| |travis| |codecov|
+| |pypi| |supported-versions| |supported-implementations|
+| |linux| |windows| |mac| |bsd|
+
+.. |docs| image:: https://img.shields.io/readthedocs/jinxed.svg?style=plastic&logo=read-the-docs
+ :target: https://jinxed.readthedocs.org
+ :alt: Documentation Status
+
+.. |appveyor| image:: https://img.shields.io/appveyor/ci/Rockhopper-Technologies/jinxed.svg?style=plastic&logo=appveyor
+ :target: https://ci.appveyor.com/project/Rockhopper-Technologies/jinxed
+ :alt: Appveyor Build Status
+
+.. |travis| image:: https://img.shields.io/travis/com/Rockhopper-Technologies/jinxed.svg?style=plastic&logo=travis
+ :target: https://travis-ci.com/Rockhopper-Technologies/jinxed
+ :alt: Travis-CI Build Status
+
+.. |codecov| image:: https://img.shields.io/codecov/c/github/Rockhopper-Technologies/jinxed.svg?style=plastic&logo=codecov
+ :target: https://codecov.io/gh/Rockhopper-Technologies/jinxed
+ :alt: Coverage Status
+
+.. |pypi| image:: https://img.shields.io/pypi/v/jinxed.svg?style=plastic&logo=pypi
+ :alt: PyPI Package latest release
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |supported-versions| image:: https://img.shields.io/pypi/pyversions/jinxed.svg?style=plastic&logo=pypi
+ :alt: Supported versions
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/jinxed.svg?style=plastic&logo=pypi
+ :alt: Supported implementations
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |linux| image:: https://img.shields.io/badge/Linux-yes-success?style=plastic&logo=linux
+ :alt: Linux supported
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |windows| image:: https://img.shields.io/badge/Windows-yes-success?style=plastic&logo=windows
+ :alt: Windows supported
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |mac| image:: https://img.shields.io/badge/MacOS-yes-success?style=plastic&logo=apple
+ :alt: MacOS supported
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. |bsd| image:: https://img.shields.io/badge/BSD-yes-success?style=plastic&logo=freebsd
+ :alt: BSD supported
+ :target: https://pypi.python.org/pypi/jinxed
+
+.. end-badges
+
+
+Overview
+========
+
+Jinxed is an implementation of a subset of the Python curses_ library.
+It provides pure Python implementations of terminfo functions such as `tigetstr()`_
+and `tparm()`_ as well as convenience methods for working with Windows terminals.
+
+Jinxed was initially written to support Blessed_ on Windows, but will work on all platforms.
+
+
+Installation
+============
+
+.. code-block:: console
+
+ $ pip install jinxed
+
+
+Documentation
+=============
+
+Jinxed documentation can be found on `Read the Docs <https://jinxed.readthedocs.io/en/stable/>`_.
+
+.. _Blessed: https://pypi.org/project/blessed
+.. _curses: https://docs.python.org/library/curses.html
+.. _tigetstr(): https://docs.python.org/library/curses.html#curses.tigetstr
+.. _tparm(): https://docs.python.org/library/curses.html#curses.tparm
+
diff --git a/third_party/python/jinxed/jinxed-1.2.0.dist-info/RECORD b/third_party/python/jinxed/jinxed-1.2.0.dist-info/RECORD
new file mode 100644
index 0000000000..2929aa63a9
--- /dev/null
+++ b/third_party/python/jinxed/jinxed-1.2.0.dist-info/RECORD
@@ -0,0 +1,18 @@
+jinxed/__init__.py,sha256=SiIICY1hCXKflXonUVMsB6tnX0HlBOqmTvStTGJlkWU,1047
+jinxed/_keys.py,sha256=2UeEOVCPBgy5fv6HKaW_TxmHI03QwqEv_TiKGB5lSCI,2535
+jinxed/_terminal.py,sha256=kdYG-8E9rIgMCXxzEVA19-q01EYm2TQWxvr5vCPnnyY,3330
+jinxed/_tparm.py,sha256=sn1P8_4VsSsgHYgco1va-Bk2eQTColtPTj3aAa3QR7A,8833
+jinxed/_util.py,sha256=kcxjcHhGX7cqrlYlBYc03dsez3RCx899OzPgQ_L4jmE,1462
+jinxed/has_key.py,sha256=J9nU62s2KZcndOud1b8x_B3uBsZonGfqPLWan9Kh5Jw,4269
+jinxed/win32.py,sha256=oIpfwPRAAq4kBJGXA5pnaapaYW7ubO72sF2HEZeY2uM,10256
+jinxed/terminfo/__init__.py,sha256=63dZbYG1TkSJwWbm_2rEfmBjMalOO-gBj1pHEvCaTNg,5088
+jinxed/terminfo/ansicon.py,sha256=X3dLufLBpFwX8ouKJMt7Ia3Xu7rCKxKI9pQEYFlAD5E,4313
+jinxed/terminfo/vtwin10.py,sha256=W4sqWtH0p-lzd-5u0q_wkePNhbKtJX_UeDksPBnYp5o,2057
+jinxed/terminfo/xterm.py,sha256=NIPuVWIWvhF4ClQxewGlRnVxBKq2j1iV1knKdG7WA1I,30525
+jinxed/terminfo/xterm_256color.py,sha256=Xi6I7LbIy2F4hmpzXf51YK1utdWWKUNqEWlpHb39isM,792
+jinxed/terminfo/xterm_256colors.py,sha256=02ci_cybpc_qNw-guktEth-JduVTspDCats4QaEtOjQ,793
+jinxed-1.2.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
+jinxed-1.2.0.dist-info/METADATA,sha256=pXE3x-jb9pFccBO8qpKUp2HSbBc_JmNoJ4XfcOVPxgQ,4272
+jinxed-1.2.0.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110
+jinxed-1.2.0.dist-info/top_level.txt,sha256=B6kZZ8ObbPHjOIuhpS6zxE9lGfnpHp5KthpsDuXIXR0,7
+jinxed-1.2.0.dist-info/RECORD,,
diff --git a/third_party/python/jinxed/jinxed-1.2.0.dist-info/WHEEL b/third_party/python/jinxed/jinxed-1.2.0.dist-info/WHEEL
new file mode 100644
index 0000000000..01b8fc7d4a
--- /dev/null
+++ b/third_party/python/jinxed/jinxed-1.2.0.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.36.2)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/third_party/python/jinxed/jinxed-1.2.0.dist-info/top_level.txt b/third_party/python/jinxed/jinxed-1.2.0.dist-info/top_level.txt
new file mode 100644
index 0000000000..6f38c7da7f
--- /dev/null
+++ b/third_party/python/jinxed/jinxed-1.2.0.dist-info/top_level.txt
@@ -0,0 +1 @@
+jinxed
diff --git a/third_party/python/jinxed/jinxed/__init__.py b/third_party/python/jinxed/jinxed/__init__.py
new file mode 100644
index 0000000000..19b826930b
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/__init__.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 - 2021 Avram Lubkin, All Rights Reserved
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Jinxed Terminal Library
+
+Jinxed is an implementation of a subset of the Python curses library for Windows
+
+Other libraries implement the full curses stack. Jinxed is intended primarily for libraries
+that need to access terminfo functions such as tigetstr() and tparm().
+"""
+
+# flake8: noqa: F401
+
+from jinxed._keys import *
+from jinxed._tparm import tparm
+from jinxed._terminal import setupterm, tigetflag, tigetnum, tigetstr
+from jinxed._util import error, IS_WINDOWS
+
+if IS_WINDOWS: # pragma: no branch
+ from jinxed.win32 import get_term # pragma: no cover
+else:
+ from jinxed._util import get_term
+
+
+__version__ = '1.2.0'
+
+COLOR_BLACK = 0
+COLOR_RED = 1
+COLOR_GREEN = 2
+COLOR_YELLOW = 3
+COLOR_BLUE = 4
+COLOR_MAGENTA = 5
+COLOR_CYAN = 6
+COLOR_WHITE = 7
diff --git a/third_party/python/jinxed/jinxed/_keys.py b/third_party/python/jinxed/jinxed/_keys.py
new file mode 100644
index 0000000000..559e0f5879
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/_keys.py
@@ -0,0 +1,164 @@
+"""
+Key code constants
+
+Most of this information came from the terminfo man pages, part of ncurses
+More information on ncurses can be found at:
+https://www.gnu.org/software/ncurses/ncurses.html
+"""
+
+KEY_A1 = 348
+KEY_A3 = 349
+KEY_B2 = 350
+KEY_BACKSPACE = 263
+KEY_BEG = 354
+KEY_BREAK = 257
+KEY_BTAB = 353
+KEY_C1 = 351
+KEY_C3 = 352
+KEY_CANCEL = 355
+KEY_CATAB = 342
+KEY_CLEAR = 333
+KEY_CLOSE = 356
+KEY_COMMAND = 357
+KEY_COPY = 358
+KEY_CREATE = 359
+KEY_CTAB = 341
+KEY_DC = 330
+KEY_DL = 328
+KEY_DOWN = 258
+KEY_EIC = 332
+KEY_END = 360
+KEY_ENTER = 343
+KEY_EOL = 335
+KEY_EOS = 334
+KEY_EXIT = 361
+KEY_F0 = 264
+KEY_F1 = 265
+KEY_F10 = 274
+KEY_F11 = 275
+KEY_F12 = 276
+KEY_F13 = 277
+KEY_F14 = 278
+KEY_F15 = 279
+KEY_F16 = 280
+KEY_F17 = 281
+KEY_F18 = 282
+KEY_F19 = 283
+KEY_F2 = 266
+KEY_F20 = 284
+KEY_F21 = 285
+KEY_F22 = 286
+KEY_F23 = 287
+KEY_F24 = 288
+KEY_F25 = 289
+KEY_F26 = 290
+KEY_F27 = 291
+KEY_F28 = 292
+KEY_F29 = 293
+KEY_F3 = 267
+KEY_F30 = 294
+KEY_F31 = 295
+KEY_F32 = 296
+KEY_F33 = 297
+KEY_F34 = 298
+KEY_F35 = 299
+KEY_F36 = 300
+KEY_F37 = 301
+KEY_F38 = 302
+KEY_F39 = 303
+KEY_F4 = 268
+KEY_F40 = 304
+KEY_F41 = 305
+KEY_F42 = 306
+KEY_F43 = 307
+KEY_F44 = 308
+KEY_F45 = 309
+KEY_F46 = 310
+KEY_F47 = 311
+KEY_F48 = 312
+KEY_F49 = 313
+KEY_F5 = 269
+KEY_F50 = 314
+KEY_F51 = 315
+KEY_F52 = 316
+KEY_F53 = 317
+KEY_F54 = 318
+KEY_F55 = 319
+KEY_F56 = 320
+KEY_F57 = 321
+KEY_F58 = 322
+KEY_F59 = 323
+KEY_F6 = 270
+KEY_F60 = 324
+KEY_F61 = 325
+KEY_F62 = 326
+KEY_F63 = 327
+KEY_F7 = 271
+KEY_F8 = 272
+KEY_F9 = 273
+KEY_FIND = 362
+KEY_HELP = 363
+KEY_HOME = 262
+KEY_IC = 331
+KEY_IL = 329
+KEY_LEFT = 260
+KEY_LL = 347
+KEY_MARK = 364
+KEY_MAX = 511
+KEY_MESSAGE = 365
+KEY_MIN = 257
+KEY_MOUSE = 409
+KEY_MOVE = 366
+KEY_NEXT = 367
+KEY_NPAGE = 338
+KEY_OPEN = 368
+KEY_OPTIONS = 369
+KEY_PPAGE = 339
+KEY_PREVIOUS = 370
+KEY_PRINT = 346
+KEY_REDO = 371
+KEY_REFERENCE = 372
+KEY_REFRESH = 373
+KEY_REPLACE = 374
+KEY_RESET = 345
+KEY_RESIZE = 410
+KEY_RESTART = 375
+KEY_RESUME = 376
+KEY_RIGHT = 261
+KEY_SAVE = 377
+KEY_SBEG = 378
+KEY_SCANCEL = 379
+KEY_SCOMMAND = 380
+KEY_SCOPY = 381
+KEY_SCREATE = 382
+KEY_SDC = 383
+KEY_SDL = 384
+KEY_SELECT = 385
+KEY_SEND = 386
+KEY_SEOL = 387
+KEY_SEXIT = 388
+KEY_SF = 336
+KEY_SFIND = 389
+KEY_SHELP = 390
+KEY_SHOME = 391
+KEY_SIC = 392
+KEY_SLEFT = 393
+KEY_SMESSAGE = 394
+KEY_SMOVE = 395
+KEY_SNEXT = 396
+KEY_SOPTIONS = 397
+KEY_SPREVIOUS = 398
+KEY_SPRINT = 399
+KEY_SR = 337
+KEY_SREDO = 400
+KEY_SREPLACE = 401
+KEY_SRESET = 344
+KEY_SRIGHT = 402
+KEY_SRSUME = 403
+KEY_SSAVE = 404
+KEY_SSUSPEND = 405
+KEY_STAB = 340
+KEY_SUNDO = 406
+KEY_SUSPEND = 407
+KEY_UNDO = 408
+KEY_UP = 259
diff --git a/third_party/python/jinxed/jinxed/_terminal.py b/third_party/python/jinxed/jinxed/_terminal.py
new file mode 100644
index 0000000000..524a67afc6
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/_terminal.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 Avram Lubkin, All Rights Reserved
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Provides a terminal class primarily for accessing functions that depend on
+a terminal which has been previously setup as well as those functions
+"""
+
+import importlib
+import io
+import platform
+import sys
+
+from jinxed.terminfo import BOOL_CAPS, NUM_CAPS
+from jinxed._util import BASESTRING, error, raise_from_none
+
+if platform.system() == 'Windows': # pragma: no branch
+ from jinxed.win32 import get_term # pragma: no cover
+else:
+ from jinxed._util import get_term
+
+
+TERM = None
+
+
+class Terminal(object):
+ """
+ Persistent terminal object for functions that require a previously configured state
+ """
+
+ def __init__(self, term=None, fd=-1): # pylint: disable=invalid-name
+
+ # Type check for term
+ if term is not None and not isinstance(term, BASESTRING):
+ raise TypeError('term must be a string or None, not %s' % type(term).__name__)
+
+ # Type check and default handling for fd
+ if fd == -1:
+ try:
+ self.stream_fd = sys.stdout.fileno()
+ except (AttributeError, TypeError, io.UnsupportedOperation):
+ self.stream_fd = None
+ elif not isinstance(fd, int):
+ raise TypeError('fd must be an integer, not %s' % type(fd).__name__)
+ else:
+ self.stream_fd = fd
+
+ # Try to dynamically determine terminal type
+ if term is None:
+ term = get_term(self.stream_fd)
+
+ try:
+ self.terminfo = importlib.import_module('jinxed.terminfo.%s' % term.replace('-', '_'))
+ except ImportError:
+ raise_from_none(error('Could not find terminal %s' % term))
+
+ def tigetstr(self, capname):
+ """
+ Reimplementation of curses.tigetstr()
+ """
+
+ return self.terminfo.STR_CAPS.get(capname, None)
+
+ def tigetnum(self, capname):
+ """
+ Reimplementation of curses.tigetnum()
+ """
+
+ return self.terminfo.NUM_CAPS.get(capname, -1 if capname in NUM_CAPS else -2)
+
+ def tigetflag(self, capname):
+ """
+ Reimplementation of curses.tigetflag()
+ """
+
+ if capname in self.terminfo.BOOL_CAPS:
+ return 1
+ if capname in BOOL_CAPS:
+ return 0
+ return -1
+
+
+def setupterm(term=None, fd=-1): # pylint: disable=invalid-name
+ """
+ Reimplementation of :py:func:`curses.setupterm`
+ """
+
+ global TERM # pylint: disable=global-statement
+ TERM = Terminal(term, fd)
+
+
+def tigetflag(capname):
+ """
+ Reimplementation of :py:func:`curses.tigetflag`
+ """
+
+ if TERM is None:
+ raise error('Must call setupterm() first')
+ return TERM.tigetflag(capname)
+
+
+def tigetnum(capname):
+ """
+ Reimplementation of :py:func:`curses.tigetnum`
+ """
+
+ if TERM is None:
+ raise error('Must call setupterm() first')
+ return TERM.tigetnum(capname)
+
+
+def tigetstr(capname):
+ """
+ Reimplementation of :py:func:`curses.tigetstr`
+ """
+
+ if TERM is None:
+ raise error('Must call setupterm() first')
+ return TERM.tigetstr(capname)
diff --git a/third_party/python/jinxed/jinxed/_tparm.py b/third_party/python/jinxed/jinxed/_tparm.py
new file mode 100644
index 0000000000..8874397a8f
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/_tparm.py
@@ -0,0 +1,291 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 Avram Lubkin, All Rights Reserved
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+An pure Python implementation of tparm
+Based on documentation in man(5) terminfo and comparing behavior of curses.tparm
+"""
+
+from collections import deque
+import operator
+import re
+
+
+OPERATORS = {b'+': operator.add,
+ b'-': operator.sub,
+ b'*': operator.mul,
+ b'/': operator.floordiv,
+ b'm': operator.mod,
+ b'&': operator.and_,
+ b'|': operator.or_,
+ b'^': operator.xor,
+ b'=': operator.eq,
+ b'>': operator.gt,
+ b'<': operator.lt,
+ b'~': operator.inv,
+ b'!': operator.not_,
+ b'A': lambda x, y: bool(x and y),
+ b'O': lambda x, y: bool(x or y)}
+
+FILTERS = (('_literal_percent', br'%%'),
+ ('_pop_c', br'%c'),
+ ('_increment_one_two', br'%i'),
+ ('_binary_op', br'%([\+\-\*/m\&\|\^=><AO])'),
+ ('_unary_op', br'%([\~!])'),
+ ('_push_param', br'%p([1-9]\d*)'),
+ ('_set_dynamic', br'%P([a-z])'),
+ ('_get_dynamic', br'%g([a-z])'),
+ ('_set_static', br'%P([A-Z])'),
+ ('_get_static', br'%g([A-Z])'),
+ ('_char_constant', br"%'(.)'"),
+ ('_int_constant', br'%{(\d+)}'),
+ ('_push_len', br'%l'),
+ ('_cond_if', br'%\?(.+?)(?=%t)'),
+ ('_cond_then_else', br'%t(.+?)(?=%e)'),
+ ('_cond_then_fi', br'%t(.+?)(?=%;)'),
+ ('_cond_else', br'%e(.+?)(?=%;|$)'),
+ ('_cond_fi', br'%;'),
+ ('_printf', br'%:?[^%]*?[doxXs]'),
+ ('_unmatched', br'%.'),
+ ('_literal', br'[^%]+'))
+
+PATTERNS = tuple((re.compile(pattern), filter_) for filter_, pattern in FILTERS)
+NULL = type('Null', (int,), {})(0)
+
+
+class TParm(object): # pylint: disable=useless-object-inheritance
+ """
+ Class to hold tparm methods and persist variables between calls
+ """
+
+ def __init__(self, *params, **kwargs):
+
+ self.rtn = b''
+ self.stack = deque()
+
+ # The spec for tparm allows c string parameters, but most implementations don't
+ # The reference code makes a best effort to determine which parameters require strings
+ # We'll allow them without trying to predict
+ for param in params:
+ if not isinstance(param, (int, bytes)):
+ raise TypeError('Parameters must be integers or bytes, not %s' %
+ type(param).__name__)
+ self.params = list(params)
+
+ static = kwargs.get('static', None)
+ self.static = {} if static is None else static
+ dynamic = kwargs.get('static', None)
+ self.dynamic = {} if dynamic is None else dynamic
+
+ def __call__(self, string, *params):
+ return self.child(*params).parse(string)
+
+ def _literal_percent(self, group): # pylint: disable=unused-argument
+ """
+ Literal percent sign
+ """
+ self.rtn += b'%'
+
+ def _pop_c(self, group): # pylint: disable=unused-argument
+ """
+ Return pop() like %c in printf
+ """
+
+ try:
+ value = self.stack.pop()
+ except IndexError:
+ value = NULL
+
+ # Treat null as 0x80
+ if value is NULL:
+ value = 0x80
+
+ self.rtn += b'%c' % value
+
+ def _increment_one_two(self, group): # pylint: disable=unused-argument
+ """
+ Add 1 to first two parameters
+ Missing parameters are treated as 0's
+ """
+ for index in (0, 1):
+ try:
+ self.params[index] += 1
+ except IndexError:
+ self.params.append(1)
+
+ def _binary_op(self, group):
+ """
+ Perform a binary operation on the last two items on the stack
+ The order of evaluation is the order the items were placed on the stack
+ """
+ second_val = self.stack.pop()
+ self.stack.append(OPERATORS[group](self.stack.pop(), second_val))
+
+ def _unary_op(self, group):
+ """
+ Perform a unary operation on the last item on the stack
+ """
+ self.stack.append(OPERATORS[group](self.stack.pop()))
+
+ def _push_param(self, group):
+ """
+ Push a parameter onto the stack
+ If the parameter is missing, push Null
+ """
+ try:
+ self.stack.append(self.params[int(group) - 1])
+ except IndexError:
+ self.stack.append(NULL)
+
+ def _set_dynamic(self, group):
+ """
+ Set the a dynamic variable to pop()
+ """
+ self.dynamic[group] = self.stack.pop()
+
+ def _get_dynamic(self, group):
+ """
+ Push the value of a dynamic variable onto the stack
+ """
+ self.stack.append(self.dynamic.get(group, NULL))
+
+ def _set_static(self, group):
+ """
+ Set the a static variable to pop()
+ """
+ self.static[group] = self.stack.pop()
+
+ def _get_static(self, group):
+ """
+ Push the value of a static variable onto the stack
+ """
+ self.stack.append(self.static.get(group, NULL))
+
+ def _char_constant(self, group):
+ """
+ Push an character constant onto the stack
+ """
+ self.stack.append(ord(group))
+
+ def _int_constant(self, group):
+ """
+ Push an integer constant onto the stack
+ """
+ self.stack.append(int(group))
+
+ def _push_len(self, group): # pylint: disable=unused-argument
+ """
+ Replace the last item on the stack with its length
+ """
+ self.stack.append(len(self.stack.pop()))
+
+ def _cond_if(self, group):
+ """
+ Recursively evaluate the body of the if statement
+ """
+ self.parse(group)
+
+ def _cond_then_else(self, group):
+ """
+ If the last item on the stack is True,
+ recursively evaluate then statement
+
+ Do not consume last item on stack
+ """
+ if self.stack[-1]:
+ self.parse(group)
+
+ def _cond_then_fi(self, group):
+ """
+ If the last item on the stack is True,
+ recursively evaluate then statement
+
+ Always consume last item on stack
+ """
+ if self.stack.pop():
+ self.parse(group)
+
+ def _cond_else(self, group):
+ """
+ If the last item on the stack is False,
+ recursively evaluate the both of the else statement
+
+ Always consume last item on stack
+ """
+ if not self.stack.pop():
+ self.parse(group)
+
+ def _cond_fi(self, group): # pylint: disable=unused-argument
+ """
+ End if statement
+ """
+
+ def _printf(self, group):
+ """
+ Subset of printf-like formatting
+ """
+
+ # : is an escape to prevent flags from being treated as % operators, ignore
+ # Python 2 returns as ':', Python 3 returns as 58
+ if group[1] in (b':', 58):
+ group = b'%' + group[2:]
+
+ try:
+ value = self.stack.pop()
+ except IndexError:
+ value = NULL
+
+ # Treat null as empty string when string formatting
+ # Python 2 returns as 's', Python 3 returns as 115
+ if value is NULL and group[-1] in (b's', 115):
+ value = b''
+
+ self.rtn += group % value
+
+ def _unmatched(self, group): # pylint: disable=unused-argument
+ """
+ Escape pattern with no spec is skipped
+ """
+
+ def _literal(self, group):
+ """
+ Anything not prefaced with a known pattern spec is treated literally
+ """
+ self.rtn += group
+
+ def parse(self, string):
+ """
+ Parsing loop
+ Evaluate regex patterns in order until a pattern is matched
+ """
+
+ if not isinstance(string, bytes):
+ raise TypeError("A bytes-like object is required, not '%s'" % type(string).__name__)
+
+ index = 0
+ length = len(string)
+
+ while index < length:
+ for filt, meth in PATTERNS: # pragma: no branch
+ match = re.match(filt, string[index:])
+ if match:
+ group = match.groups()[-1] if match.groups() else match.group(0)
+ getattr(self, meth)(group)
+ index += match.end()
+ break
+
+ return self.rtn
+
+ def child(self, *params):
+ """
+ Return a new instance with the same variables, but different parameters
+ """
+ return self.__class__(*params, static=self.static, dynamic=self.dynamic)
+
+
+tparm = TParm() # pylint: disable=invalid-name
+"""Reimplementation of :py:func:`curses.tparm`"""
diff --git a/third_party/python/jinxed/jinxed/_util.py b/third_party/python/jinxed/jinxed/_util.py
new file mode 100644
index 0000000000..7d9dd2e255
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/_util.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 - 2021 Avram Lubkin, All Rights Reserved
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Utility objects
+"""
+
+import os
+import platform
+import sys
+
+if sys.version_info[:2] < (3, 3): # pragma: no branch
+ import mock # pragma: no cover # pylint: disable=import-error, unused-import
+else:
+ from unittest import mock # noqa: F401 # pylint: disable=unused-import
+
+if sys.version_info[0] < 3: # pragma: no branch
+ BASESTRING = basestring # pragma: no cover # noqa: F821 # pylint: disable=undefined-variable
+else:
+ BASESTRING = str
+
+IS_WINDOWS = platform.system() == 'Windows'
+
+
+class error(Exception): # pylint: disable=invalid-name
+ """
+ Generic class for Jinxed errors
+ """
+
+
+def get_term(*args, **kwargs): # pylint: disable=unused-argument
+ """
+ A lightweight stand-in for win32.get_term() for non-Windows platforms
+ Returns value of TERM environment variable or 'unknown'
+ """
+
+ return os.environ.get('TERM', 'unknown')
+
+
+def raise_from_none(exc): # pragma: no cover
+ """
+ Convenience function to raise from None in a Python 2/3 compatible manner
+ """
+ raise exc
+
+
+if sys.version_info[0] >= 3: # pragma: no branch
+ exec('def raise_from_none(exc):\n raise exc from None') # pylint: disable=exec-used
diff --git a/third_party/python/jinxed/jinxed/has_key.py b/third_party/python/jinxed/jinxed/has_key.py
new file mode 100644
index 0000000000..2c9225444d
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/has_key.py
@@ -0,0 +1,158 @@
+"""
+key mapping numeric to cap
+"""
+
+from jinxed import _keys
+
+
+_capability_names = { # pylint: disable=invalid-name
+ _keys.KEY_A1: 'ka1',
+ _keys.KEY_A3: 'ka3',
+ _keys.KEY_B2: 'kb2',
+ _keys.KEY_BACKSPACE: 'kbs',
+ _keys.KEY_BEG: 'kbeg',
+ _keys.KEY_BTAB: 'kcbt',
+ _keys.KEY_C1: 'kc1',
+ _keys.KEY_C3: 'kc3',
+ _keys.KEY_CANCEL: 'kcan',
+ _keys.KEY_CATAB: 'ktbc',
+ _keys.KEY_CLEAR: 'kclr',
+ _keys.KEY_CLOSE: 'kclo',
+ _keys.KEY_COMMAND: 'kcmd',
+ _keys.KEY_COPY: 'kcpy',
+ _keys.KEY_CREATE: 'kcrt',
+ _keys.KEY_CTAB: 'kctab',
+ _keys.KEY_DC: 'kdch1',
+ _keys.KEY_DL: 'kdl1',
+ _keys.KEY_DOWN: 'kcud1',
+ _keys.KEY_EIC: 'krmir',
+ _keys.KEY_END: 'kend',
+ _keys.KEY_ENTER: 'kent',
+ _keys.KEY_EOL: 'kel',
+ _keys.KEY_EOS: 'ked',
+ _keys.KEY_EXIT: 'kext',
+ _keys.KEY_F0: 'kf0',
+ _keys.KEY_F1: 'kf1',
+ _keys.KEY_F10: 'kf10',
+ _keys.KEY_F11: 'kf11',
+ _keys.KEY_F12: 'kf12',
+ _keys.KEY_F13: 'kf13',
+ _keys.KEY_F14: 'kf14',
+ _keys.KEY_F15: 'kf15',
+ _keys.KEY_F16: 'kf16',
+ _keys.KEY_F17: 'kf17',
+ _keys.KEY_F18: 'kf18',
+ _keys.KEY_F19: 'kf19',
+ _keys.KEY_F2: 'kf2',
+ _keys.KEY_F20: 'kf20',
+ _keys.KEY_F21: 'kf21',
+ _keys.KEY_F22: 'kf22',
+ _keys.KEY_F23: 'kf23',
+ _keys.KEY_F24: 'kf24',
+ _keys.KEY_F25: 'kf25',
+ _keys.KEY_F26: 'kf26',
+ _keys.KEY_F27: 'kf27',
+ _keys.KEY_F28: 'kf28',
+ _keys.KEY_F29: 'kf29',
+ _keys.KEY_F3: 'kf3',
+ _keys.KEY_F30: 'kf30',
+ _keys.KEY_F31: 'kf31',
+ _keys.KEY_F32: 'kf32',
+ _keys.KEY_F33: 'kf33',
+ _keys.KEY_F34: 'kf34',
+ _keys.KEY_F35: 'kf35',
+ _keys.KEY_F36: 'kf36',
+ _keys.KEY_F37: 'kf37',
+ _keys.KEY_F38: 'kf38',
+ _keys.KEY_F39: 'kf39',
+ _keys.KEY_F4: 'kf4',
+ _keys.KEY_F40: 'kf40',
+ _keys.KEY_F41: 'kf41',
+ _keys.KEY_F42: 'kf42',
+ _keys.KEY_F43: 'kf43',
+ _keys.KEY_F44: 'kf44',
+ _keys.KEY_F45: 'kf45',
+ _keys.KEY_F46: 'kf46',
+ _keys.KEY_F47: 'kf47',
+ _keys.KEY_F48: 'kf48',
+ _keys.KEY_F49: 'kf49',
+ _keys.KEY_F5: 'kf5',
+ _keys.KEY_F50: 'kf50',
+ _keys.KEY_F51: 'kf51',
+ _keys.KEY_F52: 'kf52',
+ _keys.KEY_F53: 'kf53',
+ _keys.KEY_F54: 'kf54',
+ _keys.KEY_F55: 'kf55',
+ _keys.KEY_F56: 'kf56',
+ _keys.KEY_F57: 'kf57',
+ _keys.KEY_F58: 'kf58',
+ _keys.KEY_F59: 'kf59',
+ _keys.KEY_F6: 'kf6',
+ _keys.KEY_F60: 'kf60',
+ _keys.KEY_F61: 'kf61',
+ _keys.KEY_F62: 'kf62',
+ _keys.KEY_F63: 'kf63',
+ _keys.KEY_F7: 'kf7',
+ _keys.KEY_F8: 'kf8',
+ _keys.KEY_F9: 'kf9',
+ _keys.KEY_FIND: 'kfnd',
+ _keys.KEY_HELP: 'khlp',
+ _keys.KEY_HOME: 'khome',
+ _keys.KEY_IC: 'kich1',
+ _keys.KEY_IL: 'kil1',
+ _keys.KEY_LEFT: 'kcub1',
+ _keys.KEY_LL: 'kll',
+ _keys.KEY_MARK: 'kmrk',
+ _keys.KEY_MESSAGE: 'kmsg',
+ _keys.KEY_MOVE: 'kmov',
+ _keys.KEY_NEXT: 'knxt',
+ _keys.KEY_NPAGE: 'knp',
+ _keys.KEY_OPEN: 'kopn',
+ _keys.KEY_OPTIONS: 'kopt',
+ _keys.KEY_PPAGE: 'kpp',
+ _keys.KEY_PREVIOUS: 'kprv',
+ _keys.KEY_PRINT: 'kprt',
+ _keys.KEY_REDO: 'krdo',
+ _keys.KEY_REFERENCE: 'kref',
+ _keys.KEY_REFRESH: 'krfr',
+ _keys.KEY_REPLACE: 'krpl',
+ _keys.KEY_RESTART: 'krst',
+ _keys.KEY_RESUME: 'kres',
+ _keys.KEY_RIGHT: 'kcuf1',
+ _keys.KEY_SAVE: 'ksav',
+ _keys.KEY_SBEG: 'kBEG',
+ _keys.KEY_SCANCEL: 'kCAN',
+ _keys.KEY_SCOMMAND: 'kCMD',
+ _keys.KEY_SCOPY: 'kCPY',
+ _keys.KEY_SCREATE: 'kCRT',
+ _keys.KEY_SDC: 'kDC',
+ _keys.KEY_SDL: 'kDL',
+ _keys.KEY_SELECT: 'kslt',
+ _keys.KEY_SEND: 'kEND',
+ _keys.KEY_SEOL: 'kEOL',
+ _keys.KEY_SEXIT: 'kEXT',
+ _keys.KEY_SF: 'kind',
+ _keys.KEY_SFIND: 'kFND',
+ _keys.KEY_SHELP: 'kHLP',
+ _keys.KEY_SHOME: 'kHOM',
+ _keys.KEY_SIC: 'kIC',
+ _keys.KEY_SLEFT: 'kLFT',
+ _keys.KEY_SMESSAGE: 'kMSG',
+ _keys.KEY_SMOVE: 'kMOV',
+ _keys.KEY_SNEXT: 'kNXT',
+ _keys.KEY_SOPTIONS: 'kOPT',
+ _keys.KEY_SPREVIOUS: 'kPRV',
+ _keys.KEY_SPRINT: 'kPRT',
+ _keys.KEY_SR: 'kri',
+ _keys.KEY_SREDO: 'kRDO',
+ _keys.KEY_SREPLACE: 'kRPL',
+ _keys.KEY_SRIGHT: 'kRIT',
+ _keys.KEY_SRSUME: 'kRES',
+ _keys.KEY_SSAVE: 'kSAV',
+ _keys.KEY_SSUSPEND: 'kSPD',
+ _keys.KEY_STAB: 'khts',
+ _keys.KEY_SUNDO: 'kUND',
+ _keys.KEY_SUSPEND: 'kspd',
+ _keys.KEY_UNDO: 'kund',
+ _keys.KEY_UP: 'kcuu1'
+ }
diff --git a/third_party/python/jinxed/jinxed/terminfo/__init__.py b/third_party/python/jinxed/jinxed/terminfo/__init__.py
new file mode 100644
index 0000000000..8a304e9f44
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/__init__.py
@@ -0,0 +1,87 @@
+"""
+jinxed terminal info library
+
+Most of this information came from the terminfo man pages, part of ncurses
+More information on ncurses can be found at:
+https://www.gnu.org/software/ncurses/ncurses.html
+
+Boolean and numeric capabilities are listed here to support tigetnum() and tigetflag()
+"""
+
+# pylint: disable=wrong-spelling-in-comment
+
+BOOL_CAPS = [
+ 'am', # (auto_right_margin) terminal has automatic margins
+ 'bce', # (back_color_erase) screen erased with background color
+ 'bw', # (auto_left_margin) cub1 wraps from column 0 to last column
+ 'ccc', # (can_change) terminal can re-define existing colors
+ 'chts', # (hard_cursor) cursor is hard to see
+ 'cpix', # (cpi_changes_res) changing character pitch changes resolution
+ 'crxm', # (cr_cancels_micro_mode) using cr turns off micro mode
+ 'daisy', # (has_print_wheel) printer needs operator to change character set
+ 'da', # (memory_above) display may be retained above the screen
+ 'db', # (memory_below) display may be retained below the screen
+ 'eo', # (erase_overstrike) can erase overstrikes with a blank
+ 'eslok', # (status_line_esc_ok) escape can be used on the status line
+ 'gn', # (generic_type) generic line type
+ 'hc', # (hard_copy) hardcopy terminal
+ 'hls', # (hue_lightness_saturation) terminal uses only HLS color notation (Tektronix)
+ 'hs', # (has_status_line) has extra status line
+ 'hz', # (tilde_glitch) cannot print ~'s (Hazeltine)
+ 'in', # (insert_null_glitch) insert mode distinguishes nulls
+ 'km', # (has_meta_key) Has a meta key (i.e., sets 8th-bit)
+ 'lpix', # (lpi_changes_res) changing line pitch changes resolution
+ 'mc5i', # (prtr_silent) printer will not echo on screen
+ 'mir', # (move_insert_mode) safe to move while in insert mode
+ 'msgr', # (move_standout_mode) safe to move while in standout mode
+ 'ndscr', # (non_dest_scroll_region) scrolling region is non-destructive
+ 'npc', # (no_pad_char) pad character does not exist
+ 'nrrmc', # (non_rev_rmcup) smcup does not reverse rmcup
+ 'nxon', # (needs_xon_xoff) padding will not work, xon/xoff required
+ 'os', # (over_strike) terminal can overstrike
+ 'sam', # (semi_auto_right_margin) printing in last column causes cr
+ 'ul', # (transparent_underline) underline character overstrikes
+ 'xenl', # (eat_newline_glitch) newline ignored after 80 cols (concept)
+ 'xhpa', # (col_addr_glitch) only positive motion for hpa/mhpa caps
+ 'xhp', # (ceol_standout_glitch) standout not erased by overwriting (hp)
+ 'xon', # (xon_xoff) terminal uses xon/xoff handshaking
+ 'xsb', # (no_esc_ctlc) beehive (f1=escape, f2=ctrl C)
+ 'xt', # (dest_tabs_magic_smso) tabs destructive, magic so char (t1061)
+ 'xvpa', # (row_addr_glitch) only positive motion for vpa/mvpa caps
+]
+
+NUM_CAPS = [
+ 'bitwin', # (bit_image_entwining) number of passes for each bit-image row
+ 'bitype', # (bit_image_type) type of bit-image device
+ 'btns', # (buttons) number of buttons on mouse
+ 'bufsz', # (buffer_capacity) numbers of bytes buffered before printing
+ 'colors', # (max_colors) maximum number of colors on screen
+ 'cols', # (columns) number of columns in a line
+ 'cps', # (print_rate) print rate in characters per second
+ 'it', # (init_tabs) tabs initially every # spaces
+ 'lh', # (label_height) rows in each label
+ 'lines', # (lines) number of lines on screen or page
+ 'lm', # (lines_of_memory) lines of memory if > line. 0 means varies
+ 'lw', # (label_width) columns in each label
+ 'ma', # (max_attributes) maximum combined attributes terminal can handle
+ 'maddr', # (max_micro_address) maximum value in micro_..._address
+ 'mcs', # (micro_col_size) character step size when in micro mode
+ 'mjump', # (max_micro_jump) maximum value in parm_..._micro
+ 'mls', # (micro_line_size) line step size when in micro mode
+ 'ncv', # (no_color_video) video attributes that cannot be used with colors
+ 'nlab', # (num_labels) number of labels on screen
+ 'npins', # (number_of_pins) numbers of pins in print-head
+ 'orc', # (output_res_char) horizontal resolution in units per line
+ 'orhi', # (output_res_horz_inch) horizontal resolution in units per inch
+ 'orl', # (output_res_line) vertical resolution in units per line
+ 'orvi', # (output_res_vert_inch) vertical resolution in units per inch
+ 'pairs', # (max_pairs) maximum number of color-pairs on the screen
+ 'pb', # (padding_baud_rate) lowest baud rate where padding needed
+ 'spinh', # (dot_horz_spacing) spacing of dots horizontally in dots per inch
+ 'spinv', # (dot_vert_spacing) spacing of pins vertically in pins per inch
+ 'vt', # (virtual_terminal) virtual terminal number (CB/unix)
+ 'widcs', # (wide_char_size) character step size when in double wide mode
+ 'wnum', # (maximum_windows) maximum number of definable windows
+ 'wsl', # (width_status_line) number of columns in status line
+ 'xmc', # (magic_cookie_glitch) number of blank characters left by smso or rmso
+]
diff --git a/third_party/python/jinxed/jinxed/terminfo/ansicon.py b/third_party/python/jinxed/jinxed/terminfo/ansicon.py
new file mode 100644
index 0000000000..d4ee079e40
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/ansicon.py
@@ -0,0 +1,158 @@
+"""
+Ansicon virtual terminal codes
+
+Information sourced from:
+ https://github.com/adoxa/ansicon/blob/master/sequences.txt
+
+A best effort has been made, but not all information was available
+"""
+
+from .xterm_256color import BOOL_CAPS, NUM_CAPS, STR_CAPS
+
+BOOL_CAPS = BOOL_CAPS[:]
+NUM_CAPS = NUM_CAPS.copy()
+STR_CAPS = STR_CAPS.copy()
+
+
+# Added
+STR_CAPS['cht'] = b'\x1b[%p1%dI'
+STR_CAPS['cnl'] = b'\x1b[%p1%dE'
+STR_CAPS['cpl'] = b'\x1b[%p1%dF'
+STR_CAPS['da1'] = b'\x1b[0c'
+STR_CAPS['dsr'] = b'\x1b[5n'
+STR_CAPS['hvp'] = b'\x1b[%i%p1%d;%p2%df' # Same as cup
+STR_CAPS['setb'] = b'\x1b[48;5;%p1%dm'
+STR_CAPS['setf'] = b'\x1b[38;5;%p1%dm'
+
+# Removed - These do not appear to be supported
+del STR_CAPS['dim']
+del STR_CAPS['flash']
+del STR_CAPS['invis']
+del STR_CAPS['kcbt']
+del STR_CAPS['kEND']
+del STR_CAPS['kf37']
+del STR_CAPS['kf38']
+del STR_CAPS['kf39']
+del STR_CAPS['kf40']
+del STR_CAPS['kf41']
+del STR_CAPS['kf42']
+del STR_CAPS['kf43']
+del STR_CAPS['kf44']
+del STR_CAPS['kf45']
+del STR_CAPS['kf46']
+del STR_CAPS['kf47']
+del STR_CAPS['kf48']
+del STR_CAPS['kf61']
+del STR_CAPS['kf62']
+del STR_CAPS['kf63']
+del STR_CAPS['kIC']
+del STR_CAPS['kind']
+del STR_CAPS['kLFT']
+del STR_CAPS['kmous']
+del STR_CAPS['kNXT']
+del STR_CAPS['kPRV']
+del STR_CAPS['kri']
+del STR_CAPS['kRIT']
+del STR_CAPS['meml']
+del STR_CAPS['memu']
+del STR_CAPS['ritm']
+del STR_CAPS['rmam']
+del STR_CAPS['rmcup']
+del STR_CAPS['rmir']
+del STR_CAPS['rmkx']
+del STR_CAPS['rmm']
+del STR_CAPS['sitm']
+del STR_CAPS['smam']
+del STR_CAPS['smcup']
+del STR_CAPS['smir']
+del STR_CAPS['smkx']
+del STR_CAPS['smm']
+
+# Modified
+NUM_CAPS['colors'] = 16
+NUM_CAPS['cols'] = 80
+NUM_CAPS['lines'] = 30
+NUM_CAPS['pairs'] = 256
+STR_CAPS['cbt'] = b'\x1b[%p1%dZ'
+STR_CAPS['cnorm'] = b'\x1b[?25h'
+STR_CAPS['csr'] = b'\x1b[%p1%{1}%+%d;%?%p2%t%p2%{1}%+%dr'
+STR_CAPS['cub1'] = b'\x1b[D'
+STR_CAPS['cud1'] = b'\x1b[B'
+STR_CAPS['cvvis'] = b'\x1b[?25h'
+STR_CAPS['initc'] = b'\x1b]4;%p1%d;rgb] =%p2%d/%p3%d/%p4%d\x1b'
+STR_CAPS['is2'] = b'\x1b[!p\x1b>'
+STR_CAPS['ka1'] = b'\x00G' # upper left of keypad
+STR_CAPS['ka3'] = b'\x00I' # lower right of keypad
+STR_CAPS['kbs'] = b'\x08'
+STR_CAPS['kc1'] = b'\x00O' # lower left of keypad
+STR_CAPS['kc3'] = b'\x00Q' # lower right of keypad
+STR_CAPS['kcub1'] = b'\xe0K'
+STR_CAPS['kcud1'] = b'\xe0P'
+STR_CAPS['kcuf1'] = b'\xe0M'
+STR_CAPS['kcuu1'] = b'\xe0H'
+STR_CAPS['kDC'] = b'\xe0S'
+STR_CAPS['kdch1'] = b'\x0eQ'
+STR_CAPS['kend'] = b'\xe0O'
+STR_CAPS['kent'] = b'\r'
+STR_CAPS['kf1'] = b'\x00;'
+STR_CAPS['kf2'] = b'\x00<'
+STR_CAPS['kf3'] = b'\x00='
+STR_CAPS['kf4'] = b'\x00>'
+STR_CAPS['kf5'] = b'\x00?'
+STR_CAPS['kf6'] = b'\x00@'
+STR_CAPS['kf7'] = b'\x00A'
+STR_CAPS['kf8'] = b'\x00B'
+STR_CAPS['kf9'] = b'\x00C'
+STR_CAPS['kf10'] = b'\x00D'
+STR_CAPS['kf11'] = b'\xe0\x85'
+STR_CAPS['kf12'] = b'\xe0\x86'
+STR_CAPS['kf13'] = b'\x00T'
+STR_CAPS['kf14'] = b'\x00U'
+STR_CAPS['kf15'] = b'\x00V'
+STR_CAPS['kf16'] = b'\x00W'
+STR_CAPS['kf17'] = b'\x00X'
+STR_CAPS['kf18'] = b'\x00Y'
+STR_CAPS['kf19'] = b'\x00Z'
+STR_CAPS['kf20'] = b'\x00['
+STR_CAPS['kf21'] = b'\x00\\'
+STR_CAPS['kf22'] = b'\x00]'
+STR_CAPS['kf23'] = b'\xe0\x87'
+STR_CAPS['kf24'] = b'\xe0\x88'
+STR_CAPS['kf25'] = b'\x00^'
+STR_CAPS['kf26'] = b'\x00_'
+STR_CAPS['kf27'] = b'\x00`'
+STR_CAPS['kf28'] = b'\x00a'
+STR_CAPS['kf29'] = b'\x00b'
+STR_CAPS['kf30'] = b'\x00c'
+STR_CAPS['kf31'] = b'\x00d'
+STR_CAPS['kf32'] = b'\x00e'
+STR_CAPS['kf33'] = b'\x00f'
+STR_CAPS['kf34'] = b'\x00g'
+STR_CAPS['kf35'] = b'\xe0\x89'
+STR_CAPS['kf36'] = b'\xe0\x8a'
+# Missing F37 - F48
+STR_CAPS['kf49'] = b'\x00h'
+STR_CAPS['kf50'] = b'\x00i'
+STR_CAPS['kf51'] = b'\x00j'
+STR_CAPS['kf52'] = b'\x00k'
+STR_CAPS['kf53'] = b'\x00l'
+STR_CAPS['kf54'] = b'\x00m'
+STR_CAPS['kf55'] = b'\x00n'
+STR_CAPS['kf56'] = b'\x00o'
+STR_CAPS['kf57'] = b'\x00p'
+STR_CAPS['kf58'] = b'\x00q'
+STR_CAPS['kf59'] = b'\xe0\x8b'
+STR_CAPS['kf60'] = b'\xe0\x8b'
+# Missing F61 - F63
+STR_CAPS['khome'] = b'\xe0G'
+STR_CAPS['kich1'] = b'\xe0R'
+STR_CAPS['knp'] = b'\xe0Q'
+STR_CAPS['kpp'] = b'\xe0I'
+STR_CAPS['rs1'] = b'\x1bc\x1b]104ST'
+STR_CAPS['rs2'] = b'\x1b[!p'
+STR_CAPS['sgr'] = b'\x1b[%p1%d%?%p2%t;%p2%d%;%?%p3%t;%p3%d%;%?%p4%t;%p4%d%;%?%p5%t;%p5%d%;' \
+ b'%?%p6%t;%p6%d%;%?%p7%t;%p7%d%;%?%p8%t;%p8%d%;%?%p9%t;%p9%d%;m'
+
+# Need info - Left in, but unsure
+# acsc (covers some, but maybe not all)
+# mc0/mc4/mc5 (print screen/off/on)
diff --git a/third_party/python/jinxed/jinxed/terminfo/vtwin10.py b/third_party/python/jinxed/jinxed/terminfo/vtwin10.py
new file mode 100644
index 0000000000..6cfb0deb69
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/vtwin10.py
@@ -0,0 +1,68 @@
+"""
+Windows 10 virtual terminal codes
+
+Information sourced from:
+ https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+
+A best effort has been made, but not all information was available
+"""
+
+from .xterm_256color import BOOL_CAPS, NUM_CAPS, STR_CAPS
+
+BOOL_CAPS = BOOL_CAPS[:]
+NUM_CAPS = NUM_CAPS.copy()
+STR_CAPS = STR_CAPS.copy()
+
+# Added
+STR_CAPS['cht'] = b'\x1b[%p1%dI'
+STR_CAPS['cnl'] = b'\x1b[%p1%dE'
+STR_CAPS['cpl'] = b'\x1b[%p1%dF'
+STR_CAPS['hvp'] = b'\x1b[%i%p1%d;%p2%df' # Same as cup
+STR_CAPS['ka1'] = b'\x1bOH' # upper left of keypad
+STR_CAPS['ka3'] = b'\x1b[5~' # upper right of keypad
+STR_CAPS['setb'] = b'\x1b[48;5;%p1%dm'
+STR_CAPS['setf'] = b'\x1b[38;5;%p1%dm'
+
+# Removed - These do not appear to be supported
+del STR_CAPS['blink']
+del STR_CAPS['dim']
+del STR_CAPS['flash']
+del STR_CAPS['invis']
+del STR_CAPS['kmous']
+del STR_CAPS['meml']
+del STR_CAPS['memu']
+del STR_CAPS['ritm']
+del STR_CAPS['rmam']
+del STR_CAPS['rmir']
+del STR_CAPS['rmm']
+del STR_CAPS['sitm']
+del STR_CAPS['smam']
+del STR_CAPS['smir']
+del STR_CAPS['smm']
+
+# Modified
+NUM_CAPS['colors'] = 256
+NUM_CAPS['cols'] = 120
+NUM_CAPS['lines'] = 30
+NUM_CAPS['pairs'] = 65536
+STR_CAPS['cbt'] = b'\x1b[%p1%dZ'
+STR_CAPS['csr'] = b'\x1b[%p1%{1}%+%d;%?%p2%t%p2%{1}%+%dr'
+STR_CAPS['cub1'] = b'\x1b[D'
+STR_CAPS['cud1'] = b'\x1b[B'
+STR_CAPS['cvvis'] = b'\x1b[?25h'
+STR_CAPS['initc'] = b'\x1b]4;%p1%d;rgb] =%p2%d/%p3%d/%p4%d\x1b'
+STR_CAPS['is2'] = b'\x1b[!p\x1b>'
+STR_CAPS['kbs'] = b'\x7f'
+STR_CAPS['kc1'] = b'\x1bOF' # lower left of keypad
+STR_CAPS['kc3'] = b'\x1b[6~' # lower right of keypad
+STR_CAPS['kent'] = b'\r'
+STR_CAPS['rmcup'] = b'\x1b[?1049l'
+STR_CAPS['rs2'] = b'\x1b[!p\x1b>' # DECSTR
+STR_CAPS['sgr'] = b'\x1b[%p1%d%?%p2%t;%p2%d%;%?%p3%t;%p3%d%;%?%p4%t;%p4%d%;%?%p5%t;%p5%d%;' \
+ b'%?%p6%t;%p6%d%;%?%p7%t;%p7%d%;%?%p8%t;%p8%d%;%?%p9%t;%p9%d%;m'
+STR_CAPS['smcup'] = b'\x1b[?1049h'
+STR_CAPS['u9'] = b'\x1b[0c'
+
+# Need info - Left in, but unsure
+# acsc (covers some, but maybe not all)
+# mc0/mc4/mc5 (print screen/off/on)
diff --git a/third_party/python/jinxed/jinxed/terminfo/xterm.py b/third_party/python/jinxed/jinxed/terminfo/xterm.py
new file mode 100644
index 0000000000..1a43c5184e
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/xterm.py
@@ -0,0 +1,482 @@
+"""
+xterm terminal info
+
+Since most of the Windows virtual processing schemes are based on xterm
+This file is intended to be sourced and includes the man page descriptions
+
+Most of this information came from the terminfo man pages, part of ncurses
+More information on ncurses can be found at:
+https://www.gnu.org/software/ncurses/ncurses.html
+
+The values are as reported by infocmp on Fedora 30 with ncurses 6.1
+"""
+
+# pylint: disable=wrong-spelling-in-comment,line-too-long
+# flake8: noqa: E501
+
+BOOL_CAPS = [
+ 'am', # (auto_right_margin) terminal has automatic margins
+ 'bce', # (back_color_erase) screen erased with background color
+ # 'bw', # (auto_left_margin) cub1 wraps from column 0 to last column
+ # 'ccc', # (can_change) terminal can re-define existing colors
+ # 'chts', # (hard_cursor) cursor is hard to see
+ # 'cpix', # (cpi_changes_res) changing character pitch changes resolution
+ # 'crxm', # (cr_cancels_micro_mode) using cr turns off micro mode
+ # 'daisy', # (has_print_wheel) printer needs operator to change character set
+ # 'da', # (memory_above) display may be retained above the screen
+ # 'db', # (memory_below) display may be retained below the screen
+ # 'eo', # (erase_overstrike) can erase overstrikes with a blank
+ # 'eslok', # (status_line_esc_ok) escape can be used on the status line
+ # 'gn', # (generic_type) generic line type
+ # 'hc', # (hard_copy) hardcopy terminal
+ # 'hls', # (hue_lightness_saturation) terminal uses only HLS color notation (Tektronix)
+ # 'hs', # (has_status_line) has extra status line
+ # 'hz', # (tilde_glitch) cannot print ~'s (Hazeltine)
+ # 'in', # (insert_null_glitch) insert mode distinguishes nulls
+ 'km', # (has_meta_key) Has a meta key (i.e., sets 8th-bit)
+ # 'lpix', # (lpi_changes_res) changing line pitch changes resolution
+ 'mc5i', # (prtr_silent) printer will not echo on screen
+ 'mir', # (move_insert_mode) safe to move while in insert mode
+ 'msgr', # (move_standout_mode) safe to move while in standout mode
+ # 'ndscr', # (non_dest_scroll_region) scrolling region is non-destructive
+ 'npc', # (no_pad_char) pad character does not exist
+ # 'nrrmc', # (non_rev_rmcup) smcup does not reverse rmcup
+ # 'nxon', # (needs_xon_xoff) padding will not work, xon/xoff required
+ # 'os', # (over_strike) terminal can overstrike
+ # 'sam', # (semi_auto_right_margin) printing in last column causes cr
+ # 'ul', # (transparent_underline) underline character overstrikes
+ 'xenl', # (eat_newline_glitch) newline ignored after 80 cols (concept)
+ # 'xhpa', # (col_addr_glitch) only positive motion for hpa/mhpa caps
+ # 'xhp', # (ceol_standout_glitch) standout not erased by overwriting (hp)
+ # 'xon', # (xon_xoff) terminal uses xon/xoff handshaking
+ # 'xsb', # (no_esc_ctlc) beehive (f1=escape, f2=ctrl C)
+ # 'xt', # (dest_tabs_magic_smso) tabs destructive, magic so char (t1061)
+ # 'xvpa', # (row_addr_glitch) only positive motion for vpa/mvpa caps
+]
+
+NUM_CAPS = {
+ # 'bitwin': 0, # (bit_image_entwining) number of passes for each bit-image row
+ # 'bitype': 0, # (bit_image_type) type of bit-image device
+ # 'btns': 0, # (buttons) number of buttons on mouse
+ # 'bufsz': 0, # (buffer_capacity) numbers of bytes buffered before printing
+ 'colors': 8, # (max_colors) maximum number of colors on screen
+ 'cols': 80, # (columns) number of columns in a line
+ # 'cps': 0, # (print_rate) print rate in characters per second
+ 'it': 8, # (init_tabs) tabs initially every # spaces
+ # 'lh': 0, # (label_height) rows in each label
+ 'lines': 24, # (lines) number of lines on screen or page
+ # 'lm': 0, # (lines_of_memory) lines of memory if > line. 0 means varies
+ # 'lw': 0, # (label_width) columns in each label
+ # 'ma': 0, # (max_attributes) maximum combined attributes terminal can handle
+ # 'maddr': 0, # (max_micro_address) maximum value in micro_..._address
+ # 'mcs': 0, # (micro_col_size) character step size when in micro mode
+ # 'mjump': 0, # (max_micro_jump) maximum value in parm_..._micro
+ # 'mls': 0, # (micro_line_size) line step size when in micro mode
+ # 'ncv': 0, # (no_color_video) video attributes that cannot be used with colors
+ # 'nlab': 0, # (num_labels) number of labels on screen
+ # 'npins': 0, # (number_of_pins) numbers of pins in print-head
+ # 'orc': 0, # (output_res_char) horizontal resolution in units per line
+ # 'orhi': 0, # (output_res_horz_inch) horizontal resolution in units per inch
+ # 'orl': 0, # (output_res_line) vertical resolution in units per line
+ # 'orvi': 0, # (output_res_vert_inch) vertical resolution in units per inch
+ 'pairs': 64, # (max_pairs) maximum number of color-pairs on the screen
+ # 'pb': 0, # (padding_baud_rate) lowest baud rate where padding needed
+ # 'spinh': 0, # (dot_horz_spacing) spacing of dots horizontally in dots per inch
+ # 'spinv': 0, # (dot_vert_spacing) spacing of pins vertically in pins per inch
+ # 'vt': 0, # (virtual_terminal) virtual terminal number (CB/unix)
+ # 'widcs': 0, # (wide_char_size) character step size when in double wide mode
+ # 'wnum': 0, # (maximum_windows) maximum number of definable windows
+ # 'wsl': 0, # (width_status_line) number of columns in status line
+ # 'xmc': 0, # (magic_cookie_glitch) number of blank characters left by smso or rmso
+}
+
+STR_CAPS = {
+ 'acsc': b'``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~', # (acs_chars) graphics charset pairs, based on vt100
+ 'bel': b'^G', # (bell) audible signal (bell) (P)
+ # 'bicr': b'', # (bit_image_carriage_return) Move to beginning of same row
+ # 'binel': b'', # (bit_image_newline) Move to next row of the bit image
+ # 'birep': b'', # (bit_image_repeat) Repeat bit image cell #1 #2 times
+ 'blink': b'\x1b[5m', # (enter_blink_mode) turn on blinking
+ 'bold': b'\x1b[1m', # (enter_bold_mode) turn on bold (extra bright) mode
+ 'cbt': b'\x1b[Z', # (back_tab) back tab (P)
+ # 'chr': b'', # (change_res_horz) Change horizontal resolution to #1
+ 'civis': b'\x1b[?25l', # (cursor_invisible) make cursor invisible
+ 'clear': b'\x1b[H\x1b[2J', # (clear_screen) clear screen and home cursor (P*)
+ # 'cmdch': b'', # (command_character) terminal settable cmd character in prototype !?
+ 'cnorm': b'\x1b[?12l\x1b[?25h', # (cursor_normal) make cursor appear normal (undo civis/cvvis)
+ # 'colornm': b'', # (color_names) Give name for color #1
+ # 'cpi': b'', # (change_char_pitch) Change number of characters per inch to #1
+ 'cr': b'\r', # (carriage_return) carriage return (P*) (P*)
+ # 'csin': b'', # (code_set_init) Init sequence for multiple codesets
+ # 'csnm': b'', # (char_set_names) Produce #1'th item from list of character set names
+ 'csr': b'\x1b[%i%p1%d;%p2%dr', # (change_scroll_region) change region to line #1 to line #2 (P)
+ 'cub1': b'^H', # (cursor_left) move left one space
+ 'cub': b'\x1b[%p1%dD', # (parm_left_cursor) move #1 characters to the left (P)
+ 'cud1': b'\n', # (cursor_down) down one line
+ 'cud': b'\x1b[%p1%dB', # (parm_down_cursor) down #1 lines (P*)
+ 'cuf1': b'\x1b[C', # (cursor_right) non-destructive space (move right one space)
+ 'cuf': b'\x1b[%p1%dC', # (parm_right_cursor) move #1 characters to the right (P*)
+ 'cup': b'\x1b[%i%p1%d;%p2%dH', # (cursor_address) move to row #1 columns #2
+ 'cuu1': b'\x1b[A', # (cursor_up) up one line
+ 'cuu': b'\x1b[%p1%dA', # (parm_up_cursor) up #1 lines (P*)
+ # 'cvr': b'', # (change_res_vert) Change vertical resolution to #1
+ 'cvvis': b'\x1b[?12;25h', # (cursor_visible) make cursor very visible
+ # 'cwin': b'', # (create_window) define a window #1 from #2,#3 to #4,#5
+ 'dch1': b'\x1b[P', # (delete_character) delete character (P*)
+ 'dch': b'\x1b[%p1%dP', # (parm_dch) delete #1 characters (P*)
+ # 'dclk': b'', # (display_clock) display clock
+ # 'defbi': b'', # (define_bit_image_region) Define rectangular bit image region
+ # 'defc': b'', # (define_char) Define a character #1, #2 dots wide, descender #3
+ # 'devt': b'', # (device_type) Indicate language/codeset support
+ # 'dial': b'', # (dial_phone) dial number #1
+ 'dim': b'\x1b[2m', # (enter_dim_mode) turn on half-bright mode
+ # 'dispc': b'', # (display_pc_char) Display PC character #1
+ 'dl1': b'\x1b[M', # (delete_line) delete line (P*)
+ 'dl': b'\x1b[%p1%dM', # (parm_delete_line) delete #1 lines (P*)
+ # 'docr': b'', # (these_cause_cr) Printing any of these characters causes CR
+ # 'dsl': b'', # (dis_status_line) disable status line
+ 'ech': b'\x1b[%p1%dX', # (erase_chars) erase #1 characters (P)
+ 'ed': b'\x1b[J', # (clr_eos) clear to end of screen (P*)
+ 'el1': b'\x1b[1K', # (clr_bol) Clear to beginning of line
+ 'el': b'\x1b[K', # (clr_eol) clear to end of line (P)
+ # 'enacs': b'', # (ena_acs) enable alternate char set
+ # 'endbi': b'', # (end_bit_image_region) End a bit-image region
+ # 'ff': b'', # (form_feed) hardcopy terminal page eject (P*)
+ 'flash': b'\x1b[?5h$<100/>\x1b[?5l', # (flash_screen) visible bell (may not move cursor)
+ # 'fln': b'', # (label_format) label format
+ # 'fsl': b'', # (from_status_line) return from status line
+ # 'getm': b'', # (get_mouse) Curses should get button events, parameter #1 not documented.
+ # 'hd': b'', # (down_half_line) half a line down
+ 'home': b'\x1b[H', # (cursor_home) home cursor (if no cup)
+ # 'hook': b'', # (flash_hook) flash switch hook
+ 'hpa': b'\x1b[%i%p1%dG', # (column_address) horizontal position #1, absolute (P)
+ 'ht': b'^I', # (tab) tab to next 8-space hardware tab stop
+ 'hts': b'\x1bH', # (set_tab) set a tab in every row, current columns
+ # 'hu': b'', # (up_half_line) half a line up
+ # 'hup': b'', # (hangup) hang-up phone
+ # 'ich1': b'', # (insert_character) insert character (P)
+ 'ich': b'\x1b[%p1%d@', # (parm_ich) insert #1 characters (P*)
+ # 'if': b'', # (init_file) name of initialization file
+ 'il1': b'\x1b[L', # (insert_line) insert line (P*)
+ 'il': b'\x1b[%p1%dL', # (parm_insert_line) insert #1 lines (P*)
+ 'ind': b'\n', # (scroll_forward) scroll text up (P)
+ 'indn': b'\x1b[%p1%dS', # (parm_index) scroll forward #1 lines (P)
+ # 'initc': b'', # (initialize_color) initialize color #1 to (#2,#3,#4)
+ # 'initp': b'', # (initialize_pair) Initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)
+ 'invis': b'\x1b[8m', # (enter_secure_mode) turn on blank mode (characters invisible)
+ # 'ip': b'', # (insert_padding) insert padding after inserted character
+ # 'iprog': b'', # (init_prog) path name of program for initialization
+ # 'is1': b'', # (init_1string) initialization string
+ 'is2': b'\x1b[!p\x1b[?3;4l\x1b[4l\x1b>', # (init_2string) initialization string
+ # 'is3': b'', # (init_3string) initialization string
+ # 'ka1': b'', # (key_a1) upper left of keypad
+ # 'ka3': b'', # (key_a3) upper right of keypad
+ 'kb2': b'\x1bOE', # (key_b2) center of keypad
+ # 'kbeg': b'', # (key_beg) begin key
+ # 'kBEG': b'', # (key_sbeg) shifted begin key
+ 'kbs': b'^?', # (key_backspace) backspace key
+ # 'kc1': b'', # (key_c1) lower left of keypad
+ # 'kc3': b'', # (key_c3) lower right of keypad
+ # 'kcan': b'', # (key_cancel) cancel key
+ # 'kCAN': b'', # (key_scancel) shifted cancel key
+ 'kcbt': b'\x1b[Z', # (key_btab) back-tab key
+ # 'kclo': b'', # (key_close) close key
+ # 'kclr': b'', # (key_clear) clear-screen or erase key
+ # 'kcmd': b'', # (key_command) command key
+ # 'kCMD': b'', # (key_scommand) shifted command key
+ # 'kcpy': b'', # (key_copy) copy key
+ # 'kCPY': b'', # (key_scopy) shifted copy key
+ # 'kcrt': b'', # (key_create) create key
+ # 'kCRT': b'', # (key_screate) shifted create key
+ # 'kctab': b'', # (key_ctab) clear-tab key
+ 'kcub1': b'\x1bOD', # (key_left) left-arrow key
+ 'kcud1': b'\x1bOB', # (key_down) down-arrow key
+ 'kcuf1': b'\x1bOC', # (key_right) right-arrow key
+ 'kcuu1': b'\x1bOA', # (key_up) up-arrow key
+ 'kDC': b'\x1b[3;2~', # (key_sdc) shifted delete- character key
+ 'kdch1': b'\x1b[3~', # (key_dc) delete-character key
+ # 'kdl1': b'', # (key_dl) delete-line key
+ # 'kDL': b'', # (key_sdl) shifted delete-line key
+ # 'ked': b'', # (key_eos) clear-to-end-of- screen key
+ # 'kel': b'', # (key_eol) clear-to-end-of-line key
+ 'kEND': b'\x1b[1;2F', # (key_send) shifted end key
+ 'kend': b'\x1bOF', # (key_end) end key
+ 'kent': b'\x1bOM', # (key_enter) enter/send key
+ # 'kEOL': b'', # (key_seol) shifted clear-to- end-of-line key
+ # 'kext': b'', # (key_exit) exit key
+ # 'kEXT': b'', # (key_sexit) shifted exit key
+ # 'kf0': b'', # (key_f0) F0 function key
+ 'kf1': b'\x1bOP', # (key_f1) F1 function key
+ 'kf2': b'\x1bOQ', # (key_f2) F2 function key
+ 'kf3': b'\x1bOR', # (key_f3) F3 function key
+ 'kf4': b'\x1bOS', # (key_f4) F4 function key
+ 'kf5': b'\x1b[15~', # (key_f5) F5 function key
+ 'kf6': b'\x1b[17~', # (key_f6) F6 function key
+ 'kf7': b'\x1b[18~', # (key_f7) F7 function key
+ 'kf8': b'\x1b[19~', # (key_f8) F8 function key
+ 'kf9': b'\x1b[20~', # (key_f9) F9 function key
+ 'kf10': b'\x1b[21~', # (key_f10) F10 function key
+ 'kf11': b'\x1b[23~', # (key_f11) F11 function key
+ 'kf12': b'\x1b[24~', # (key_f12) F12 function key
+ 'kf13': b'\x1b[1;2P', # (key_f13) F13 function key
+ 'kf14': b'\x1b[1;2Q', # (key_f14) F14 function key
+ 'kf15': b'\x1b[1;2R', # (key_f15) F15 function key
+ 'kf16': b'\x1b[1;2S', # (key_f16) F16 function key
+ 'kf17': b'\x1b[15;2~', # (key_f17) F17 function key
+ 'kf18': b'\x1b[17;2~', # (key_f18) F18 function key
+ 'kf19': b'\x1b[18;2~', # (key_f19) F19 function key
+ 'kf20': b'\x1b[19;2~', # (key_f20) F20 function key
+ 'kf21': b'\x1b[20;2~', # (key_f21) F21 function key
+ 'kf22': b'\x1b[21;2~', # (key_f22) F22 function key
+ 'kf23': b'\x1b[23;2~', # (key_f23) F23 function key
+ 'kf24': b'\x1b[24;2~', # (key_f24) F24 function key
+ 'kf25': b'\x1b[1;5P', # (key_f25) F25 function key
+ 'kf26': b'\x1b[1;5Q', # (key_f26) F26 function key
+ 'kf27': b'\x1b[1;5R', # (key_f27) F27 function key
+ 'kf28': b'\x1b[1;5S', # (key_f28) F28 function key
+ 'kf29': b'\x1b[15;5~', # (key_f29) F29 function key
+ 'kf30': b'\x1b[17;5~', # (key_f30) F30 function key
+ 'kf31': b'\x1b[18;5~', # (key_f31) F31 function key
+ 'kf32': b'\x1b[19;5~', # (key_f32) F32 function key
+ 'kf33': b'\x1b[20;5~', # (key_f33) F33 function key
+ 'kf34': b'\x1b[21;5~', # (key_f34) F34 function key
+ 'kf35': b'\x1b[23;5~', # (key_f35) F35 function key
+ 'kf36': b'\x1b[24;5~', # (key_f36) F36 function key
+ 'kf37': b'\x1b[1;6P', # (key_f37) F37 function key
+ 'kf38': b'\x1b[1;6Q', # (key_f38) F38 function key
+ 'kf39': b'\x1b[1;6R', # (key_f39) F39 function key
+ 'kf40': b'\x1b[1;6S', # (key_f40) F40 function key
+ 'kf41': b'\x1b[15;6~', # (key_f41) F41 function key
+ 'kf42': b'\x1b[17;6~', # (key_f42) F42 function key
+ 'kf43': b'\x1b[18;6~', # (key_f43) F43 function key
+ 'kf44': b'\x1b[19;6~', # (key_f44) F44 function key
+ 'kf45': b'\x1b[20;6~', # (key_f45) F45 function key
+ 'kf46': b'\x1b[21;6~', # (key_f46) F46 function key
+ 'kf47': b'\x1b[23;6~', # (key_f47) F47 function key
+ 'kf48': b'\x1b[24;6~', # (key_f48) F48 function key
+ 'kf49': b'\x1b[1;3P', # (key_f49) F49 function key
+ 'kf50': b'\x1b[1;3Q', # (key_f50) F50 function key
+ 'kf51': b'\x1b[1;3R', # (key_f51) F51 function key
+ 'kf52': b'\x1b[1;3S', # (key_f52) F52 function key
+ 'kf53': b'\x1b[15;3~', # (key_f53) F53 function key
+ 'kf54': b'\x1b[17;3~', # (key_f54) F54 function key
+ 'kf55': b'\x1b[18;3~', # (key_f55) F55 function key
+ 'kf56': b'\x1b[19;3~', # (key_f56) F56 function key
+ 'kf57': b'\x1b[20;3~', # (key_f57) F57 function key
+ 'kf58': b'\x1b[21;3~', # (key_f58) F58 function key
+ 'kf59': b'\x1b[23;3~', # (key_f59) F59 function key
+ 'kf60': b'\x1b[24;3~', # (key_f60) F60 function key
+ 'kf61': b'\x1b[1;4P', # (key_f61) F61 function key
+ 'kf62': b'\x1b[1;4Q', # (key_f62) F62 function key
+ 'kf63': b'\x1b[1;4R', # (key_f63) F63 function key
+ # 'kfnd': b'', # (key_find) find key
+ # 'kFND': b'', # (key_sfind) shifted find key
+ # 'khlp': b'', # (key_help) help key
+ # 'kHLP': b'', # (key_shelp) shifted help key
+ 'kHOM': b'\x1b[1;2H', # (key_shome) shifted home key
+ 'khome': b'\x1bOH', # (key_home) home key
+ # 'khts': b'', # (key_stab) set-tab key
+ 'kIC': b'\x1b[2;2~', # (key_sic) shifted insert- character key
+ 'kich1': b'\x1b[2~', # (key_ic) insert-character key
+ # 'kil1': b'', # (key_il) insert-line key
+ 'kind': b'\x1b[1;2B', # (key_sf) scroll-forward key
+ 'kLFT': b'\x1b[1;2D', # (key_sleft) shifted left-arrow key
+ # 'kll': b'', # (key_ll) lower-left key (home down)
+ 'kmous': b'\x1b[<', # (key_mouse) Mouse event has occurred
+ # 'kmov': b'', # (key_move) move key
+ # 'kMOV': b'', # (key_smove) shifted move key
+ # 'kmrk': b'', # (key_mark) mark key
+ # 'kmsg': b'', # (key_message) message key
+ # 'kMSG': b'', # (key_smessage) shifted message key
+ 'knp': b'\x1b[6~', # (key_npage) next-page key
+ # 'knxt': b'', # (key_next) next key
+ 'kNXT': b'\x1b[6;2~', # (key_snext) shifted next key
+ # 'kopn': b'', # (key_open) open key
+ # 'kopt': b'', # (key_options) options key
+ # 'kOPT': b'', # (key_soptions) shifted options key
+ 'kpp': b'\x1b[5~', # (key_ppage) previous-page key
+ # 'kprt': b'', # (key_print) print key
+ # 'kPRT': b'', # (key_sprint) shifted print key
+ # 'kprv': b'', # (key_previous) previous key
+ 'kPRV': b'\x1b[5;2~', # (key_sprevious) shifted previous key
+ # 'krdo': b'', # (key_redo) redo key
+ # 'kRDO': b'', # (key_sredo) shifted redo key
+ # 'kref': b'', # (key_reference) reference key
+ # 'kres': b'', # (key_resume) resume key
+ # 'kRES': b'', # (key_srsume) shifted resume key
+ # 'krfr': b'', # (key_refresh) refresh key
+ 'kri': b'\x1b[1;2A', # (key_sr) scroll-backward key
+ 'kRIT': b'\x1b[1;2C', # (key_sright) shifted right-arrow key
+ # 'krmir': b'', # (key_eic) sent by rmir or smir in insert mode
+ # 'krpl': b'', # (key_replace) replace key
+ # 'kRPL': b'', # (key_sreplace) shifted replace key
+ # 'krst': b'', # (key_restart) restart key
+ # 'ksav': b'', # (key_save) save key
+ # 'kSAV': b'', # (key_ssave) shifted save key
+ # 'kslt': b'', # (key_select) select key
+ # 'kSPD': b'', # (key_ssuspend) shifted suspend key
+ # 'kspd': b'', # (key_suspend) suspend key
+ # 'ktbc': b'', # (key_catab) clear-all-tabs key
+ # 'kUND': b'', # (key_sundo) shifted undo key
+ # 'kund': b'', # (key_undo) undo key
+ # 'lf0': b'', # (lab_f0) label on function key f0 if not f0
+ # 'lf10': b'', # (lab_f10) label on function key f10 if not f10
+ # 'lf1': b'', # (lab_f1) label on function key f1 if not f1
+ # 'lf2': b'', # (lab_f2) label on function key f2 if not f2
+ # 'lf3': b'', # (lab_f3) label on function key f3 if not f3
+ # 'lf4': b'', # (lab_f4) label on function key f4 if not f4
+ # 'lf5': b'', # (lab_f5) label on function key f5 if not f5
+ # 'lf6': b'', # (lab_f6) label on function key f6 if not f6
+ # 'lf7': b'', # (lab_f7) label on function key f7 if not f7
+ # 'lf8': b'', # (lab_f8) label on function key f8 if not f8
+ # 'lf9': b'', # (lab_f9) label on function key f9 if not f9
+ # 'll': b'', # (cursor_to_ll) last line, first column (if no cup)
+ # 'lpi': b'', # (change_line_pitch) Change number of lines per inch to #1
+ 'meml': b'\x1bl', # lock memory above the curser
+ 'memu': b'\x1bl', # unlock memory above the curser
+ 'mc0': b'\x1b[i', # (print_screen) print contents of screen
+ 'mc4': b'\x1b[4i', # (prtr_off) turn off printer
+ 'mc5': b'\x1b[5i', # (prtr_on) turn on printer
+ # 'mc5p': b'', # (prtr_non) turn on printer for #1 bytes
+ # 'mcub1': b'', # (micro_left) Like cursor_left in micro mode
+ # 'mcub': b'', # (parm_left_micro) Like parm_left_cursor in micro mode
+ # 'mcud1': b'', # (micro_down) Like cursor_down in micro mode
+ # 'mcud': b'', # (parm_down_micro) Like parm_down_cursor in micro mode
+ # 'mcuf1': b'', # (micro_right) Like cursor_right in micro mode
+ # 'mcuf': b'', # (parm_right_micro) Like parm_right_cursor in micro mode
+ # 'mcuu1': b'', # (micro_up) Like cursor_up in micro mode
+ # 'mcuu': b'', # (parm_up_micro) Like parm_up_cursor in micro mode
+ # 'mgc': b'', # (clear_margins) clear right and left soft margins
+ # 'mhpa': b'', # (micro_column_address) Like column_address in micro mode
+ # 'minfo': b'', # (mouse_info) Mouse status information
+ # 'mrcup': b'', # (cursor_mem_address) memory relative cursor addressing, move to row #1 columns #2
+ # 'mvpa': b'', # (micro_row_address) Like row_address #1 in micro mode
+ # 'nel': b'', # (newline) newline (behave like cr followed by lf)
+ # 'oc': b'', # (orig_colors) Set all color pairs to the original ones
+ 'op': b'\x1b[39;49m', # (orig_pair) Set default pair to its original value
+ # 'pad': b'', # (pad_char) padding char (instead of null)
+ # 'pause': b'', # (fixed_pause) pause for 2-3 seconds
+ # 'pctrm': b'', # (pc_term_options) PC terminal options
+ # 'pfkey': b'', # (pkey_key) program function key #1 to type string #2
+ # 'pfloc': b'', # (pkey_local) program function key #1 to execute string #2
+ # 'pfx': b'', # (pkey_xmit) program function key #1 to transmit string #2
+ # 'pfxl': b'', # (pkey_plab) Program function key #1 to type string #2 and show string #3
+ # 'pln': b'', # (plab_norm) program label #1 to show string #2
+ # 'porder': b'', # (order_of_pins) Match software bits to print-head pins
+ # 'prot': b'', # (enter_protected_mode) turn on protected mode
+ # 'pulse': b'', # (pulse) select pulse dialing
+ # 'qdial': b'', # (quick_dial) dial number #1 without checking
+ # 'rbim': b'', # (stop_bit_image) Stop printing bit image graphics
+ 'rc': b'\x1b8', # (restore_cursor) restore cursor to position of last save_cursor
+ # 'rcsd': b'', # (stop_char_set_def) End definition of character set #1
+ 'rep': b'%p1%c\x1b[%p2%{1}%-%db', # (repeat_char) repeat char #1 #2 times (P*)
+ # 'reqmp': b'', # (req_mouse_pos) Request mouse position
+ 'rev': b'\x1b[7m', # (enter_reverse_mode) turn on reverse video mode
+ # 'rf': b'', # (reset_file) name of reset file
+ # 'rfi': b'', # (req_for_input) send next input char (for ptys)
+ 'ri': b'\x1bM', # (scroll_reverse) scroll text down (P)
+ 'rin': b'\x1b[%p1%dT', # (parm_rindex) scroll back #1 lines (P)
+ 'ritm': b'\x1b[23m', # (exit_italics_mode) End italic mode
+ # 'rlm': b'', # (exit_leftward_mode) End left-motion mode
+ 'rmacs': b'\x1b(B', # (exit_alt_charset_mode) end alternate character set (P)
+ 'rmam': b'\x1b[?7l', # (exit_am_mode) turn off automatic margins
+ # 'rmclk': b'', # (remove_clock) remove clock
+ 'rmcup': b'\x1b[?1049l\x1b[23;0;0t', # (exit_ca_mode) strings to end programs using cup
+ # 'rmdc': b'', # (exit_delete_mode) end delete mode
+ # 'rmicm': b'', # (exit_micro_mode) End micro-motion mode
+ 'rmir': b'\x1b[4l', # (exit_insert_mode) exit insert mode
+ 'rmkx': b'\x1b[?1l\x1b>', # (keypad_local) leave 'keyboard_transmit' mode
+ # 'rmln': b'', # (label_off) turn off soft labels
+ 'rmm': b'\x1b[?1034l', # (meta_off) turn off meta mode
+ # 'rmp': b'', # (char_padding) like ip but when in insert mode
+ # 'rmpch': b'', # (exit_pc_charset_mode) Exit PC character display mode
+ # 'rmsc': b'', # (exit_scancode_mode) Exit PC scancode mode
+ 'rmso': b'\x1b[27m', # (exit_standout_mode) exit standout mode
+ 'rmul': b'\x1b[24m', # (exit_underline_mode) exit underline mode
+ # 'rmxon': b'', # (exit_xon_mode) turn off xon/xoff handshaking
+ 'rs1': b'\x1bc', # (reset_1string) reset string
+ 'rs2': b'\x1b[!p\x1b[?3;4l\x1b[4l\x1b>', # (reset_2string) reset string
+ # 'rs3': b'', # (reset_3string) reset string
+ # 'rshm': b'', # (exit_shadow_mode) End shadow-print mode
+ # 'rsubm': b'', # (exit_subscript_mode) End subscript mode
+ # 'rsupm': b'', # (exit_superscript_mode) End superscript mode
+ # 'rum': b'', # (exit_upward_mode) End reverse character motion
+ # 'rwidm': b'', # (exit_doublewide_mode) End double-wide mode
+ # 's0ds': b'', # (set0_des_seq) Shift to codeset 0 (EUC set 0, ASCII)
+ # 's1ds': b'', # (set1_des_seq) Shift to codeset 1
+ # 's2ds': b'', # (set2_des_seq) Shift to codeset 2
+ # 's3ds': b'', # (set3_des_seq) Shift to codeset 3
+ # 'sbim': b'', # (start_bit_image) Start printing bit image graphics
+ 'sc': b'\x1b7', # (save_cursor) save current cursor position (P)
+ # 'scesa': b'', # (alt_scancode_esc) Alternate escape for scancode emulation
+ # 'scesc': b'', # (scancode_escape) Escape for scancode emulation
+ # 'sclk': b'', # (set_clock) set clock, #1 hrs #2 mins #3 secs
+ # 'scp': b'', # (set_color_pair) Set current color pair to #1
+ # 'scs': b'', # (select_char_set) Select character set, #1
+ # 'scsd': b'', # (start_char_set_def) Start character set definition #1, with #2 characters in the set
+ # 'sdrfq': b'', # (enter_draft_quality) Enter draft-quality mode
+ 'setab': b'\x1b[4%p1%dm', # (set_a_background) Set background color to #1, using ANSI escape
+ 'setaf': b'\x1b[3%p1%dm', # (set_a_foreground) Set foreground color to #1, using ANSI escape
+ 'setb': b'\x1b[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m', # (set_background) Set background color #1
+ # 'setcolor': b'', # (set_color_band) Change to ribbon color #1
+ 'setf': b'\x1b[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m', # (set_foreground) Set foreground color #1
+ 'sgr0': b'\x1b(B\x1b[m', # (exit_attribute_mode) turn off all attributes
+ 'sgr': b'%?%p9%t\x1b(0%e\x1b(B%;\x1b[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m', # (set_attributes) define video attributes #1-#9 (PG9)
+ 'sitm': b'\x1b[3m', # (enter_italics_mode) Enter italic mode
+ # 'slines': b'', # (set_page_length) Set page length to #1 lines
+ # 'slm': b'', # (enter_leftward_mode) Start leftward carriage motion
+ 'smacs': b'\x1b(0', # (enter_alt_charset_mode) start alternate character set (P)
+ 'smam': b'\x1b[?7h', # (enter_am_mode) turn on automatic margins
+ 'smcup': b'\x1b[?1049h\x1b[22;0;0t', # (enter_ca_mode) string to start programs using cup
+ # 'smdc': b'', # (enter_delete_mode) enter delete mode
+ # 'smgb': b'', # (set_bottom_margin) Set bottom margin at current line
+ # 'smgbp': b'', # (set_bottom_margin_parm) Set bottom margin at line #1 or (if smgtp is not given) #2 lines from bottom
+ # 'smgl': b'', # (set_left_margin) set left soft margin at current column. See smgl. (ML is not in BSD termcap).
+ # 'smglp': b'', # (set_left_margin_parm) Set left (right) margin at column #1
+ # 'smglr': b'', # (set_lr_margin) Set both left and right margins to #1, #2. (ML is not in BSD termcap).
+ # 'smgr': b'', # (set_right_margin) set right soft margin at current column
+ # 'smgrp': b'', # (set_right_margin_parm) Set right margin at column #1
+ # 'smgtb': b'', # (set_tb_margin) Sets both top and bottom margins to #1, #2
+ # 'smgt': b'', # (set_top_margin) Set top margin at current line
+ # 'smgtp': b'', # (set_top_margin_parm) Set top (bottom) margin at row #1
+ # 'smicm': b'', # (enter_micro_mode) Start micro-motion mode
+ 'smir': b'\x1b[4h', # (enter_insert_mode) enter insert mode
+ 'smkx': b'\x1b[?1h\x1b=', # (keypad_xmit) enter 'keyboard_transmit' mode
+ # 'smln': b'', # (label_on) turn on soft labels
+ 'smm': b'\x1b[?1034h', # (meta_on) turn on meta mode (8th-bit on)
+ # 'smpch': b'', # (enter_pc_charset_mode) Enter PC character display mode
+ # 'smsc': b'', # (enter_scancode_mode) Enter PC scancode mode
+ 'smso': b'\x1b[7m', # (enter_standout_mode) begin standout mode
+ 'smul': b'\x1b[4m', # (enter_underline_mode) begin underline mode
+ # 'smxon': b'', # (enter_xon_mode) turn on xon/xoff handshaking
+ # 'snlq': b'', # (enter_near_letter_quality) Enter NLQ mode
+ # 'snrmq': b'', # (enter_normal_quality) Enter normal-quality mode
+ # 'sshm': b'', # (enter_shadow_mode) Enter shadow-print mode
+ # 'ssubm': b'', # (enter_subscript_mode) Enter subscript mode
+ # 'ssupm': b'', # (enter_superscript_mode) Enter superscript mode
+ # 'subcs': b'', # (subscript_characters) List of subscriptable characters
+ # 'sum': b'', # (enter_upward_mode) Start upward carriage motion
+ # 'supcs': b'', # (superscript_characters) List of superscriptable characters
+ # 'swidm': b'', # (enter_doublewide_mode) Enter double-wide mode
+ 'tbc': b'\x1b[3g', # (clear_all_tabs) clear all tab stops (P)
+ # 'tone': b'', # (tone) select touch tone dialing
+ # 'tsl': b'', # (to_status_line) move to status line, column #1
+ # 'u0': b'', # (user0) User string #0
+ # 'u1': b'', # (user1) User string #1
+ # 'u2': b'', # (user2) User string #2
+ # 'u3': b'', # (user3) User string #3
+ # 'u4': b'', # (user4) User string #4
+ # 'u5': b'', # (user5) User string #5
+ 'u6': b'\x1b[%i%d;%dR', # (user6) User string #6 [cursor position report (equiv. to ANSI/ECMA-48 CPR)]
+ 'u7': b'\x1b[6n', # (user7) User string #7 [cursor position request (equiv. to VT100/ANSI/ECMA-48 DSR 6)]
+ 'u8': b'\x1b[?%[;0123456789]c', # (user8) User string #8 [terminal answerback description]
+ 'u9': b'\x1b[c', # (user9) User string #9 [terminal enquire string (equiv. to ANSI/ECMA-48 DA)]
+ # 'uc': b'', # (underline_char) underline char and move past it
+ 'vpa': b'\x1b[%i%p1%dd', # (row_address) vertical position #1 absolute (P)
+ # 'wait': b'', # (wait_tone) wait for dial-tone
+ # 'wind': b'', # (set_window) current window is lines #1-#2 cols #3-#4
+ # 'wingo': b'', # (goto_window) go to window #1
+ # 'xoffc': b'', # (xoff_character) XOFF character
+ # 'xonc': b'', # (xon_character) XON character
+ # 'zerom': b'', # (zero_motion) No motion for subsequent character
+}
diff --git a/third_party/python/jinxed/jinxed/terminfo/xterm_256color.py b/third_party/python/jinxed/jinxed/terminfo/xterm_256color.py
new file mode 100644
index 0000000000..6c7e2c16ac
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/xterm_256color.py
@@ -0,0 +1,28 @@
+"""
+xterm-256color terminal info
+
+The values are as reported by infocmp on Fedora 30 with ncurses 6.1
+"""
+
+from .xterm import BOOL_CAPS, NUM_CAPS, STR_CAPS
+
+BOOL_CAPS = BOOL_CAPS[:]
+NUM_CAPS = NUM_CAPS.copy()
+STR_CAPS = STR_CAPS.copy()
+
+# Added
+BOOL_CAPS.append('ccc')
+STR_CAPS['initc'] = b'\x1b]4;%p1%d;rgb\x5c:%p2%{255}%*%{1000}%/%2.2X/' \
+ b'%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\x1b\x5c'
+STR_CAPS['oc'] = b'\x1b]104\007'
+
+# Removed
+del STR_CAPS['setb']
+del STR_CAPS['setf']
+
+# Modified
+NUM_CAPS['colors'] = 256
+NUM_CAPS['pairs'] = 65536
+STR_CAPS['rs1'] = b'\x1bc\x1b]104\007'
+STR_CAPS['setab'] = b'\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m'
+STR_CAPS['setaf'] = b'\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m'
diff --git a/third_party/python/jinxed/jinxed/terminfo/xterm_256colors.py b/third_party/python/jinxed/jinxed/terminfo/xterm_256colors.py
new file mode 100644
index 0000000000..1e005a1bd9
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/terminfo/xterm_256colors.py
@@ -0,0 +1,28 @@
+"""
+xterm-256colors terminal info
+
+The values are as reported by infocmp on Fedora 30 with ncurses 6.1
+"""
+
+from .xterm import BOOL_CAPS, NUM_CAPS, STR_CAPS
+
+BOOL_CAPS = BOOL_CAPS[:]
+NUM_CAPS = NUM_CAPS.copy()
+STR_CAPS = STR_CAPS.copy()
+
+# Added
+BOOL_CAPS.append('ccc')
+STR_CAPS['initc'] = b'\x1b]4;%p1%d;rgb\x5c:%p2%{255}%*%{1000}%/%2.2X/' \
+ b'%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\x1b\x5c'
+STR_CAPS['oc'] = b'\x1b]104\007'
+
+# Removed
+del STR_CAPS['setb']
+del STR_CAPS['setf']
+
+# Modified
+NUM_CAPS['colors'] = 256
+NUM_CAPS['pairs'] = 65536
+STR_CAPS['rs1'] = b'\x1bc\x1b]104\007'
+STR_CAPS['setab'] = b'\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m'
+STR_CAPS['setaf'] = b'\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m'
diff --git a/third_party/python/jinxed/jinxed/win32.py b/third_party/python/jinxed/jinxed/win32.py
new file mode 100644
index 0000000000..593a275a0a
--- /dev/null
+++ b/third_party/python/jinxed/jinxed/win32.py
@@ -0,0 +1,352 @@
+# -*- coding: utf-8 -*-
+# Copyright 2019 - 2021 Avram Lubkin, All Rights Reserved
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Support functions and wrappers for calls to the Windows API
+"""
+
+import atexit
+import codecs
+from collections import namedtuple
+import ctypes
+from ctypes import wintypes
+import io
+import msvcrt # pylint: disable=import-error
+import os
+import platform
+import sys
+
+from jinxed._util import mock, IS_WINDOWS
+
+# Workaround for auto-doc generation on Linux
+if not IS_WINDOWS:
+ ctypes = mock.Mock() # noqa: F811
+
+LPDWORD = ctypes.POINTER(wintypes.DWORD)
+COORD = wintypes._COORD # pylint: disable=protected-access
+
+# Console input modes
+ENABLE_ECHO_INPUT = 0x0004
+ENABLE_EXTENDED_FLAGS = 0x0080
+ENABLE_INSERT_MODE = 0x0020
+ENABLE_LINE_INPUT = 0x0002
+ENABLE_MOUSE_INPUT = 0x0010
+ENABLE_PROCESSED_INPUT = 0x0001
+ENABLE_QUICK_EDIT_MODE = 0x0040
+ENABLE_WINDOW_INPUT = 0x0008
+ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
+
+# Console output modes
+ENABLE_PROCESSED_OUTPUT = 0x0001
+ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
+ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+DISABLE_NEWLINE_AUTO_RETURN = 0x0008
+ENABLE_LVB_GRID_WORLDWIDE = 0x0010
+
+if IS_WINDOWS and tuple(int(num) for num in platform.version().split('.')) >= (10, 0, 10586):
+ VTMODE_SUPPORTED = True
+ CBREAK_MODE = ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT
+ RAW_MODE = ENABLE_VIRTUAL_TERMINAL_INPUT
+else:
+ VTMODE_SUPPORTED = False
+ CBREAK_MODE = ENABLE_PROCESSED_INPUT
+ RAW_MODE = 0
+
+GTS_SUPPORTED = hasattr(os, 'get_terminal_size')
+TerminalSize = namedtuple('TerminalSize', ('columns', 'lines'))
+
+
+class ConsoleScreenBufferInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
+ """
+ Python representation of CONSOLE_SCREEN_BUFFER_INFO structure
+ https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
+ """
+
+ _fields_ = [('dwSize', COORD),
+ ('dwCursorPosition', COORD),
+ ('wAttributes', wintypes.WORD),
+ ('srWindow', wintypes.SMALL_RECT),
+ ('dwMaximumWindowSize', COORD)]
+
+
+CSBIP = ctypes.POINTER(ConsoleScreenBufferInfo)
+
+
+def _check_bool(result, func, args): # pylint: disable=unused-argument
+ """
+ Used as an error handler for Windows calls
+ Gets last error if call is not successful
+ """
+
+ if not result:
+ raise ctypes.WinError(ctypes.get_last_error())
+ return args
+
+
+KERNEL32 = ctypes.WinDLL('kernel32', use_last_error=True)
+
+KERNEL32.GetConsoleCP.errcheck = _check_bool
+KERNEL32.GetConsoleCP.argtypes = tuple()
+
+KERNEL32.GetConsoleMode.errcheck = _check_bool
+KERNEL32.GetConsoleMode.argtypes = (wintypes.HANDLE, LPDWORD)
+
+KERNEL32.SetConsoleMode.errcheck = _check_bool
+KERNEL32.SetConsoleMode.argtypes = (wintypes.HANDLE, wintypes.DWORD)
+
+KERNEL32.GetConsoleScreenBufferInfo.errcheck = _check_bool
+KERNEL32.GetConsoleScreenBufferInfo.argtypes = (wintypes.HANDLE, CSBIP)
+
+
+def get_csbi(filehandle=None):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+
+ Returns:
+ :py:class:`ConsoleScreenBufferInfo`: CONSOLE_SCREEN_BUFFER_INFO_ structure
+
+ Wrapper for GetConsoleScreenBufferInfo_
+
+ If ``filehandle`` is :py:data:`None`, uses the filehandle of :py:data:`sys.__stdout__`.
+
+ """
+
+ if filehandle is None:
+ filehandle = msvcrt.get_osfhandle(sys.__stdout__.fileno())
+
+ csbi = ConsoleScreenBufferInfo()
+ KERNEL32.GetConsoleScreenBufferInfo(filehandle, ctypes.byref(csbi))
+ return csbi
+
+
+def get_console_input_encoding():
+ """
+ Returns:
+ int: Current console mode
+
+ Query for the console input code page and provide an encoding
+
+ If the code page can not be resolved to a Python encoding, :py:data:`None` is returned.
+ """
+
+ try:
+ encoding = 'cp%d' % KERNEL32.GetConsoleCP()
+ except OSError:
+ return None
+
+ try:
+ codecs.lookup(encoding)
+ except LookupError:
+ return None
+
+ return encoding
+
+
+def get_console_mode(filehandle):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+
+ Returns:
+ int: Current console mode
+
+ Raises:
+ OSError: Error calling Windows API
+
+ Wrapper for GetConsoleMode_
+ """
+
+ mode = wintypes.DWORD()
+ KERNEL32.GetConsoleMode(filehandle, ctypes.byref(mode))
+ return mode.value
+
+
+def set_console_mode(filehandle, mode):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+ mode(int): Desired console mode
+
+ Raises:
+ OSError: Error calling Windows API
+
+ Wrapper for SetConsoleMode_
+ """
+
+ return bool(KERNEL32.SetConsoleMode(filehandle, mode))
+
+
+def setcbreak(filehandle):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+
+ Raises:
+ OSError: Error calling Windows API
+
+ Convenience function which mimics :py:func:`tty.setcbreak` behavior
+
+ All console input options are disabled except ``ENABLE_PROCESSED_INPUT``
+ and, if supported, ``ENABLE_VIRTUAL_TERMINAL_INPUT``
+ """
+
+ set_console_mode(filehandle, CBREAK_MODE)
+
+
+def setraw(filehandle):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+
+ Raises:
+ OSError: Error calling Windows API
+
+ Convenience function which mimics :py:func:`tty.setraw` behavior
+
+ All console input options are disabled except, if supported, ``ENABLE_VIRTUAL_TERMINAL_INPUT``
+ """
+
+ set_console_mode(filehandle, RAW_MODE)
+
+
+def enable_vt_mode(filehandle=None):
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+
+ Raises:
+ OSError: Error calling Windows API
+
+ Enables virtual terminal processing mode for the given console
+
+ If ``filehandle`` is :py:data:`None`, uses the filehandle of :py:data:`sys.__stdout__`.
+ """
+
+ if filehandle is None:
+ filehandle = msvcrt.get_osfhandle(sys.__stdout__.fileno())
+
+ mode = get_console_mode(filehandle)
+ mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
+ set_console_mode(filehandle, mode)
+
+
+def get_terminal_size(fd): # pylint: disable=invalid-name
+ """
+ Args:
+ fd(int): Python file descriptor
+
+ Returns:
+ :py:class:`os.terminal_size`: Named tuple representing terminal size
+
+ Convenience function for getting terminal size
+
+ In Python 3.3 and above, this is a wrapper for :py:func:`os.get_terminal_size`.
+ In older versions of Python, this function calls GetConsoleScreenBufferInfo_.
+ """
+
+ # In Python 3.3+ we can let the standard library handle this
+ if GTS_SUPPORTED:
+ return os.get_terminal_size(fd)
+
+ handle = msvcrt.get_osfhandle(fd)
+ window = get_csbi(handle).srWindow
+ return TerminalSize(window.Right - window.Left + 1, window.Bottom - window.Top + 1)
+
+
+def flush_and_set_console(fd, mode): # pylint: disable=invalid-name
+ """
+ Args:
+ filehandle(int): Windows filehandle object as returned by :py:func:`msvcrt.get_osfhandle`
+ mode(int): Desired console mode
+
+ Attempts to set console to specified mode, but will not raise on failure
+
+ If the file descriptor is STDOUT or STDERR, attempts to flush first
+ """
+
+ try:
+ if fd in (sys.__stdout__.fileno(), sys.__stderr__.fileno()):
+ sys.__stdout__.flush()
+ sys.__stderr__.flush()
+ except (AttributeError, TypeError, io.UnsupportedOperation):
+ pass
+
+ try:
+ filehandle = msvcrt.get_osfhandle(fd)
+ set_console_mode(filehandle, mode)
+ except OSError:
+ pass
+
+
+def get_term(fd, fallback=True): # pylint: disable=invalid-name
+ """
+ Args:
+ fd(int): Python file descriptor
+ fallback(bool): Use fallback terminal type if type can not be determined
+ Returns:
+ str: Terminal type
+
+ Attempts to determine and enable the current terminal type
+
+ The current logic is:
+
+ - If TERM is defined in the environment, the value is returned
+ - Else, if ANSICON is defined in the environment, ``'ansicon'`` is returned
+ - Else, if virtual terminal mode is natively supported,
+ it is enabled and ``'vtwin10'`` is returned
+ - Else, if ``fallback`` is ``True``, Ansicon is loaded, and ``'ansicon'`` is returned
+ - If no other conditions are satisfied, ``'unknown'`` is returned
+
+ This logic may change in the future as additional terminal types are added.
+ """
+
+ # First try TERM
+ term = os.environ.get('TERM', None)
+
+ if term is None:
+
+ # See if ansicon is enabled
+ if os.environ.get('ANSICON', None):
+ term = 'ansicon'
+
+ # See if Windows Terminal is being used
+ elif os.environ.get('WT_SESSION', None):
+ term = 'vtwin10'
+
+ # See if the version of Windows supports VTMODE
+ elif VTMODE_SUPPORTED:
+ try:
+ filehandle = msvcrt.get_osfhandle(fd)
+ mode = get_console_mode(filehandle)
+ except OSError:
+ term = 'unknown'
+ else:
+ atexit.register(flush_and_set_console, fd, mode)
+ # pylint: disable=unsupported-binary-operation
+ set_console_mode(filehandle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ term = 'vtwin10'
+
+ # Currently falling back to Ansicon for older versions of Windows
+ elif fallback:
+ import ansicon # pylint: disable=import-error,import-outside-toplevel
+ ansicon.load()
+
+ try:
+ filehandle = msvcrt.get_osfhandle(fd)
+ mode = get_console_mode(filehandle)
+ except OSError:
+ term = 'unknown'
+ else:
+ atexit.register(flush_and_set_console, fd, mode)
+ set_console_mode(filehandle, mode ^ ENABLE_WRAP_AT_EOL_OUTPUT)
+ term = 'ansicon'
+
+ else:
+ term = 'unknown'
+
+ return term