зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1744340 - Vendor `blessed` at `1.19.1` r=firefox-build-system-reviewers,glandium
- Also vendored various `blessed` dependencies - Added an exclusion for "ansicon" and vendored a "dummy" of it so that we don't vendor the DLLs it includes. It should rarely be needed in practice, and with the dummy in place it should just fail gracefully in the event that it is needed. Differential Revision: https://phabricator.services.mozilla.com/D160405
This commit is contained in:
Родитель
3b12c51788
Коммит
1a4af2563a
|
@ -30,6 +30,12 @@ EXCLUDED_PACKAGES = {
|
|||
# The moz.build file isn't a vendored module, so don't delete it.
|
||||
"moz.build",
|
||||
"requirements.in",
|
||||
# The ansicon package contains DLLs and we don't want to arbitrarily vendor
|
||||
# them since they could be unsafe. This module should rarely be used in practice
|
||||
# (it's a fallback for old versions of windows). We've intentionally vendored a
|
||||
# modified 'dummy' version of it so that the dependency checks still succeed, but
|
||||
# if it ever is attempted to be used, it will fail gracefully.
|
||||
"ansicon",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,9 +56,11 @@ vendored:testing/web-platform/tests/tools/wptserve
|
|||
vendored:testing/web-platform/tests/tools/wptrunner
|
||||
pth:testing/xpcshell
|
||||
vendored:third_party/python/aiohttp
|
||||
vendored:third_party/python/ansicon
|
||||
vendored:third_party/python/appdirs
|
||||
vendored:third_party/python/async_timeout
|
||||
vendored:third_party/python/attrs
|
||||
vendored:third_party/python/blessed
|
||||
vendored:third_party/python/blessings
|
||||
vendored:third_party/python/cbor2
|
||||
vendored:third_party/python/certifi
|
||||
|
@ -82,6 +84,7 @@ vendored:third_party/python/idna-ssl
|
|||
vendored:third_party/python/importlib_metadata
|
||||
vendored:third_party/python/iso8601
|
||||
vendored:third_party/python/Jinja2
|
||||
vendored:third_party/python/jinxed
|
||||
vendored:third_party/python/jsmin
|
||||
vendored:third_party/python/json-e
|
||||
vendored:third_party/python/jsonschema
|
||||
|
@ -120,6 +123,7 @@ vendored:third_party/python/tqdm
|
|||
vendored:third_party/python/typing_extensions
|
||||
vendored:third_party/python/urllib3
|
||||
vendored:third_party/python/voluptuous
|
||||
vendored:third_party/python/wcwidth
|
||||
vendored:third_party/python/wheel
|
||||
vendored:third_party/python/yamllint
|
||||
vendored:third_party/python/yarl
|
||||
|
|
|
@ -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.
|
|
@ -0,0 +1,2 @@
|
|||
Name: ansicon
|
||||
Version: 1.89.0
|
|
@ -0,0 +1,6 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.31.1)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1 @@
|
|||
ansicon
|
|
@ -0,0 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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/.
|
||||
|
||||
|
||||
class Dummy(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
|
||||
_ANSICON = Dummy()
|
||||
load = _ANSICON.load
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2014 Jeff Quast
|
||||
Copyright (c) 2011 Erik Rose
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,269 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: blessed
|
||||
Version: 1.19.1
|
||||
Summary: Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities.
|
||||
Home-page: https://github.com/jquast/blessed
|
||||
Author: Jeff Quast, Erik Rose, Avram Lubkin
|
||||
Author-email: contact@jeffquast.com
|
||||
License: MIT
|
||||
Project-URL: Documentation, https://blessed.readthedocs.io
|
||||
Keywords: terminal,sequences,tty,curses,ncurses,formatting,style,color,console,keyboard,ansi,xterm
|
||||
Platform: UNKNOWN
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Environment :: Console :: Curses
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
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: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: Software Development :: User Interfaces
|
||||
Classifier: Topic :: Terminals
|
||||
Classifier: Typing :: Typed
|
||||
Requires-Python: >=2.7
|
||||
License-File: LICENSE
|
||||
Requires-Dist: wcwidth (>=0.1.4)
|
||||
Requires-Dist: six (>=1.9.0)
|
||||
Requires-Dist: jinxed (>=1.1.0) ; platform_system == "Windows"
|
||||
Requires-Dist: ordereddict (==1.1) ; python_version < "2.7"
|
||||
Requires-Dist: backports.functools-lru-cache (>=1.2.1) ; python_version < "3.2"
|
||||
|
||||
| |pypi_downloads| |codecov| |windows| |linux| |mac| |bsd|
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Blessed is an easy, practical *library* for making *terminal* apps, by providing an elegant,
|
||||
well-documented interface to Colors_, Keyboard_ input, and screen position and Location_
|
||||
capabilities.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from blessed import Terminal
|
||||
|
||||
term = Terminal()
|
||||
|
||||
print(term.home + term.clear + term.move_y(term.height // 2))
|
||||
print(term.black_on_darkkhaki(term.center('press any key to continue.')))
|
||||
|
||||
with term.cbreak(), term.hidden_cursor():
|
||||
inp = term.inkey()
|
||||
|
||||
print(term.move_down(2) + 'You pressed ' + term.bold(repr(inp)))
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_basic_intro.gif
|
||||
:alt: Animation of running the code example
|
||||
|
||||
It's meant to be *fun* and *easy*, to do basic terminal graphics and styling with Python using
|
||||
*blessed*. Terminal_ is the only class you need to import and the only object you should need for
|
||||
Terminal capabilities.
|
||||
|
||||
Whether you want to improve CLI apps with colors, or make fullscreen applications or games,
|
||||
*blessed* should help get you started quickly. Your users will love it because it works on Windows,
|
||||
Mac, and Linux, and you will love it because it has plenty of documentation and examples!
|
||||
|
||||
Full documentation at https://blessed.readthedocs.io/en/latest/
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/blessed_demo_intro.gif
|
||||
:alt: Animations of x11-colorpicker.py, bounce.py, worms.py, and plasma.py
|
||||
|
||||
x11-colorpicker.py_, bounce.py_, worms.py_, and plasma.py_, from our repository.
|
||||
|
||||
Exemplary 3rd-party examples which use *blessed*,
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_3rdparty_voltron.png
|
||||
:alt: Screenshot of 'Voltron' (By the author of Voltron, from their README).
|
||||
|
||||
Voltron_ is an extensible debugger UI toolkit written in Python
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_3rdparty_cursewords.gif
|
||||
:alt: Animation of 'cursewords' (By the author of cursewords, from their README).
|
||||
|
||||
cursewords_ is "graphical" command line program for solving crossword puzzles in the terminal.
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_3rdparty_githeat.gif
|
||||
:alt: Animation of 'githeat.interactive', using blessed repository at the time of capture.
|
||||
|
||||
GitHeat_ builds an interactive heatmap of git history.
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_3rdparty_dashing.gif
|
||||
:alt: Animations from 'Dashing' (By the author of Dashing, from their README)
|
||||
|
||||
Dashing_ is a library to quickly create terminal-based dashboards.
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/demo_3rdparty_enlighten.gif
|
||||
:alt: Animations from 'Enlighten' (By the author of Enlighten, from their README)
|
||||
|
||||
Enlighten_ is a console progress bar library that allows simultaneous output without redirection.
|
||||
|
||||
.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/blessed_3rdparty_macht.gif
|
||||
:alt: Demonstration of 'macht', a 2048 clone
|
||||
|
||||
macht_ is a clone of the (briefly popular) puzzle game, 2048.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
*Blessed* works with Windows, Mac, Linux, and BSD's, on Python 2.7, 3.4, 3.5, 3.6, 3.7, and 3.8.
|
||||
|
||||
Brief Overview
|
||||
--------------
|
||||
|
||||
*Blessed* is more than just a Python wrapper around curses_:
|
||||
|
||||
* Styles_, Colors_, and maybe a little positioning without necessarily clearing the whole screen
|
||||
first.
|
||||
* Works great with Python's new f-strings_ or any other kind of string formatting.
|
||||
* Provides up-to-the-moment Location_ and terminal height and width, so you can respond to terminal
|
||||
size changes.
|
||||
* Avoids making a mess if the output gets piped to a non-terminal, you can output sequences to any
|
||||
file-like object such as *StringIO*, files, pipes or sockets.
|
||||
* Uses `terminfo(5)`_ so it works with any terminal type and capability: No more C-like calls to
|
||||
tigetstr_ and tparm_.
|
||||
* Non-obtrusive calls to only the capabilities database ensures that you are free to mix and match
|
||||
with calls to any other curses application code or library you like.
|
||||
* Provides context managers `Terminal.fullscreen()`_ and `Terminal.hidden_cursor()`_ to safely
|
||||
express terminal modes, curses development will no longer fudge up your shell.
|
||||
* Act intelligently when somebody redirects your output to a file, omitting all of the special
|
||||
sequences colors, but still containing all of the text.
|
||||
|
||||
*Blessed* is a fork of `blessings <https://github.com/erikrose/blessings>`_, which does all of
|
||||
the same above with the same API, as well as following **enhancements**:
|
||||
|
||||
* Windows support, new since Dec. 2019!
|
||||
* Dead-simple keyboard handling: safely decoding unicode input in your system's preferred locale and
|
||||
supports application/arrow keys.
|
||||
* 24-bit color support, using `Terminal.color_rgb()`_ and `Terminal.on_color_rgb()`_ and all X11
|
||||
Colors_ by name, and not by number.
|
||||
* Determine cursor location using `Terminal.get_location()`_, enter key-at-a-time input mode using
|
||||
`Terminal.cbreak()`_ or `Terminal.raw()`_ context managers, and read timed key presses using
|
||||
`Terminal.inkey()`_.
|
||||
* Allows the *printable length* of strings that contain sequences to be determined by
|
||||
`Terminal.length()`_, supporting additional methods `Terminal.wrap()`_ and `Terminal.center()`_,
|
||||
terminal-aware variants of the built-in function `textwrap.wrap()`_ and method `str.center()`_,
|
||||
respectively.
|
||||
* Allows sequences to be removed from strings that contain them, using `Terminal.strip_seqs()`_ or
|
||||
sequences and whitespace using `Terminal.strip()`_.
|
||||
|
||||
Before And After
|
||||
----------------
|
||||
|
||||
With the built-in curses_ module, this is how you would typically
|
||||
print some underlined text at the bottom of the screen:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from curses import tigetstr, setupterm, tparm
|
||||
from fcntl import ioctl
|
||||
from os import isatty
|
||||
import struct
|
||||
import sys
|
||||
from termios import TIOCGWINSZ
|
||||
|
||||
# If we want to tolerate having our output piped to other commands or
|
||||
# files without crashing, we need to do all this branching:
|
||||
if hasattr(sys.stdout, 'fileno') and isatty(sys.stdout.fileno()):
|
||||
setupterm()
|
||||
sc = tigetstr('sc')
|
||||
cup = tigetstr('cup')
|
||||
rc = tigetstr('rc')
|
||||
underline = tigetstr('smul')
|
||||
normal = tigetstr('sgr0')
|
||||
else:
|
||||
sc = cup = rc = underline = normal = ''
|
||||
|
||||
# Save cursor position.
|
||||
print(sc)
|
||||
|
||||
if cup:
|
||||
# tigetnum('lines') doesn't always update promptly, hence this:
|
||||
height = struct.unpack('hhhh', ioctl(0, TIOCGWINSZ, '\000' * 8))[0]
|
||||
|
||||
# Move cursor to bottom.
|
||||
print(tparm(cup, height - 1, 0))
|
||||
|
||||
print('This is {under}underlined{normal}!'
|
||||
.format(under=underline, normal=normal))
|
||||
|
||||
# Restore cursor position.
|
||||
print(rc)
|
||||
|
||||
The same program with *Blessed* is simply:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from blessed import Terminal
|
||||
|
||||
term = Terminal()
|
||||
with term.location(0, term.height - 1):
|
||||
print('This is ' + term.underline('underlined') + '!', end='')
|
||||
|
||||
.. _curses: https://docs.python.org/3/library/curses.html
|
||||
.. _tigetstr: http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tigetstr.3
|
||||
.. _tparm: http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tparm.3
|
||||
.. _`terminfo(5)`: https://invisible-island.net/ncurses/man/terminfo.5.html
|
||||
.. _str.center(): https://docs.python.org/3/library/stdtypes.html#str.center
|
||||
.. _textwrap.wrap(): https://docs.python.org/3/library/textwrap.html#textwrap.wrap
|
||||
.. _Terminal: https://blessed.readthedocs.io/en/stable/terminal.html
|
||||
.. _`Terminal.fullscreen()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.fullscreen
|
||||
.. _`Terminal.get_location()`: https://blessed.readthedocs.io/en/latest/location.html#finding-the-cursor
|
||||
.. _`Terminal.color_rgb()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.color_rgb
|
||||
.. _`Terminal.hidden_cursor()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.hidden_cursor
|
||||
.. _`Terminal.on_color_rgb()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.on_color_rgb
|
||||
.. _`Terminal.length()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.length
|
||||
.. _`Terminal.strip()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.strip
|
||||
.. _`Terminal.rstrip()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.rstrip
|
||||
.. _`Terminal.lstrip()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.lstrip
|
||||
.. _`Terminal.strip_seqs()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.strip_seqs
|
||||
.. _`Terminal.wrap()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.wrap
|
||||
.. _`Terminal.center()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.center
|
||||
.. _`Terminal.rjust()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.rjust
|
||||
.. _`Terminal.ljust()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.ljust
|
||||
.. _`Terminal.cbreak()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.cbreak
|
||||
.. _`Terminal.raw()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.raw
|
||||
.. _`Terminal.inkey()`: https://blessed.readthedocs.io/en/stable/api/terminal.html#blessed.terminal.Terminal.inkey
|
||||
.. _Colors: https://blessed.readthedocs.io/en/stable/colors.html
|
||||
.. _Styles: https://blessed.readthedocs.io/en/stable/terminal.html#styles
|
||||
.. _Location: https://blessed.readthedocs.io/en/stable/location.html
|
||||
.. _Keyboard: https://blessed.readthedocs.io/en/stable/keyboard.html
|
||||
.. _Examples: https://blessed.readthedocs.io/en/stable/examples.html
|
||||
.. _x11-colorpicker.py: https://blessed.readthedocs.io/en/stable/examples.html#x11-colorpicker-py
|
||||
.. _bounce.py: https://blessed.readthedocs.io/en/stable/examples.html#bounce-py
|
||||
.. _worms.py: https://blessed.readthedocs.io/en/stable/examples.html#worms-py
|
||||
.. _plasma.py: https://blessed.readthedocs.io/en/stable/examples.html#plasma-py
|
||||
.. _Voltron: https://github.com/snare/voltron
|
||||
.. _cursewords: https://github.com/thisisparker/cursewords
|
||||
.. _GitHeat: https://github.com/AmmsA/Githeat
|
||||
.. _Dashing: https://github.com/FedericoCeratto/dashing
|
||||
.. _Enlighten: https://github.com/Rockhopper-Technologies/enlighten
|
||||
.. _macht: https://github.com/rolfmorel/macht
|
||||
.. _f-strings: https://docs.python.org/3/reference/lexical_analysis.html#f-strings
|
||||
.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/blessed.svg?logo=pypi
|
||||
:alt: Downloads
|
||||
:target: https://pypi.org/project/blessed/
|
||||
.. |codecov| image:: https://codecov.io/gh/jquast/blessed/branch/master/graph/badge.svg
|
||||
:alt: codecov.io Code Coverage
|
||||
:target: https://codecov.io/gh/jquast/blessed/
|
||||
.. |linux| image:: https://img.shields.io/badge/Linux-yes-success?logo=linux
|
||||
:alt: Linux supported
|
||||
.. |windows| image:: https://img.shields.io/badge/Windows-NEW-success?logo=windows
|
||||
:alt: Windows supported
|
||||
.. |mac| image:: https://img.shields.io/badge/MacOS-yes-success?logo=apple
|
||||
:alt: MacOS supported
|
||||
.. |bsd| image:: https://img.shields.io/badge/BSD-yes-success?logo=freebsd
|
||||
:alt: BSD supported
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
blessed/__init__.py,sha256=cVCRzlNO_XNDjs-hlDkzv5m3o5BMXxD-hVm30bbWQ1w,687
|
||||
blessed/_capabilities.py,sha256=Thj8lgDvhfM6TttvziDu0mabqZqYnwAwC3NTtSMntxc,6292
|
||||
blessed/_capabilities.pyi,sha256=If5dG9LhrIyTxUuCuV44bNxnWMk3S7Xvry3oGOBHp2k,265
|
||||
blessed/color.py,sha256=D5VmWAsZxSYIERKmkJ7FVhZgNssEtUkV8GcMbDnoxVk,7502
|
||||
blessed/color.pyi,sha256=4DNLFe-SMCVKbsvuMFLWUzNCdy45bgtZuk3wP51HlKQ,690
|
||||
blessed/colorspace.py,sha256=GEoKL18C9VrBlt-LqbhFirBuhqUmS-tyy0sb9VNJS5U,35322
|
||||
blessed/colorspace.pyi,sha256=zwo_F4rf0GSPJsW2irvxHQ3SqNlGgt7VQOFN2hXnTnw,234
|
||||
blessed/formatters.py,sha256=3QQiwMC51EdXy6-ZbCPRfw87X49jErvk2-k1yIBwk9g,19416
|
||||
blessed/formatters.pyi,sha256=gDgcWIk3pqif7SZgL5DG--GjO7QXwzen5UNgqQ_XHsw,2091
|
||||
blessed/keyboard.py,sha256=2WNuDJp_bb5tyRho6cGUup6Hqvp7bFgGDC5D5HbJ2-I,17687
|
||||
blessed/keyboard.pyi,sha256=9ibu_A44OkWKcdy_36EeHVhK4ybnurig5arrXxwVOeM,796
|
||||
blessed/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
blessed/sequences.py,sha256=Hjs2ddTcXFWqxdL_PKuMoPvaJ3gRRjsZxdy9dByXvLU,17126
|
||||
blessed/sequences.pyi,sha256=_zJkZm8S015g242mRUoEp12Qs27DS348vFqkSRsYfHc,1852
|
||||
blessed/terminal.py,sha256=QA7yt-E7U72WF7RGkfR7g_HcGAuGFalF3aUP6Zm1L6Y,59889
|
||||
blessed/terminal.pyi,sha256=ujihEHr4Ii6r8xw2UBOnAjcY1Wm7dlGbGwfLBqyQQiU,4078
|
||||
blessed/win_terminal.py,sha256=uGl52EiEq4K3udsZJHn2tlnESUHg_77fxWrEuFD77WY,5804
|
||||
blessed/win_terminal.pyi,sha256=GoS67cnj927_SXZRr1WCLD21ie_w7zlA20V33clpV7E,333
|
||||
blessed-1.19.1.dist-info/LICENSE,sha256=YBSQ1biC0QDEeC-dqb_dI_lg5reeNazESZQ5XBj01X0,1083
|
||||
blessed-1.19.1.dist-info/METADATA,sha256=H1PBstJVFYedNvC-3vOFQE0PItwv5f6wtmlKy0P5hYQ,13155
|
||||
blessed-1.19.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110
|
||||
blessed-1.19.1.dist-info/top_level.txt,sha256=2lUIfLwFZtAucvesS5UE8_MxXID5rSx_3gJ2-1JGckA,8
|
||||
blessed-1.19.1.dist-info/RECORD,,
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
blessed
|
|
@ -0,0 +1,23 @@
|
|||
"""
|
||||
A thin, practical wrapper around terminal capabilities in Python.
|
||||
|
||||
http://pypi.python.org/pypi/blessed
|
||||
"""
|
||||
# std imports
|
||||
import sys as _sys
|
||||
import platform as _platform
|
||||
|
||||
# isort: off
|
||||
if _platform.system() == 'Windows':
|
||||
from blessed.win_terminal import Terminal
|
||||
else:
|
||||
from blessed.terminal import Terminal # type: ignore
|
||||
|
||||
if (3, 0, 0) <= _sys.version_info[:3] < (3, 2, 3):
|
||||
# Good till 3.2.10
|
||||
# Python 3.x < 3.2.3 has a bug in which tparm() erroneously takes a string.
|
||||
raise ImportError('Blessed needs Python 3.2.3 or greater for Python 3 '
|
||||
'support due to http://bugs.python.org/issue10570.')
|
||||
|
||||
__all__ = ('Terminal',)
|
||||
__version__ = "1.19.1"
|
|
@ -0,0 +1,168 @@
|
|||
"""Terminal capability builder patterns."""
|
||||
# std imports
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
__all__ = (
|
||||
'CAPABILITY_DATABASE',
|
||||
'CAPABILITIES_RAW_MIXIN',
|
||||
'CAPABILITIES_ADDITIVES',
|
||||
'CAPABILITIES_CAUSE_MOVEMENT',
|
||||
)
|
||||
|
||||
CAPABILITY_DATABASE = OrderedDict((
|
||||
('bell', ('bel', {})),
|
||||
('carriage_return', ('cr', {})),
|
||||
('change_scroll_region', ('csr', {'nparams': 2})),
|
||||
('clear_all_tabs', ('tbc', {})),
|
||||
('clear_screen', ('clear', {})),
|
||||
('clr_bol', ('el1', {})),
|
||||
('clr_eol', ('el', {})),
|
||||
('clr_eos', ('clear_eos', {})),
|
||||
('column_address', ('hpa', {'nparams': 1})),
|
||||
('cursor_address', ('cup', {'nparams': 2, 'match_grouped': True})),
|
||||
('cursor_down', ('cud1', {})),
|
||||
('cursor_home', ('home', {})),
|
||||
('cursor_invisible', ('civis', {})),
|
||||
('cursor_left', ('cub1', {})),
|
||||
('cursor_normal', ('cnorm', {})),
|
||||
('cursor_report', ('u6', {'nparams': 2, 'match_grouped': True})),
|
||||
('cursor_right', ('cuf1', {})),
|
||||
('cursor_up', ('cuu1', {})),
|
||||
('cursor_visible', ('cvvis', {})),
|
||||
('delete_character', ('dch1', {})),
|
||||
('delete_line', ('dl1', {})),
|
||||
('enter_blink_mode', ('blink', {})),
|
||||
('enter_bold_mode', ('bold', {})),
|
||||
('enter_dim_mode', ('dim', {})),
|
||||
('enter_fullscreen', ('smcup', {})),
|
||||
('enter_standout_mode', ('standout', {})),
|
||||
('enter_superscript_mode', ('superscript', {})),
|
||||
('enter_susimpleript_mode', ('susimpleript', {})),
|
||||
('enter_underline_mode', ('underline', {})),
|
||||
('erase_chars', ('ech', {'nparams': 1})),
|
||||
('exit_alt_charset_mode', ('rmacs', {})),
|
||||
('exit_am_mode', ('rmam', {})),
|
||||
('exit_attribute_mode', ('sgr0', {})),
|
||||
('exit_ca_mode', ('rmcup', {})),
|
||||
('exit_fullscreen', ('rmcup', {})),
|
||||
('exit_insert_mode', ('rmir', {})),
|
||||
('exit_standout_mode', ('rmso', {})),
|
||||
('exit_underline_mode', ('rmul', {})),
|
||||
('flash_hook', ('hook', {})),
|
||||
('flash_screen', ('flash', {})),
|
||||
('insert_line', ('il1', {})),
|
||||
('keypad_local', ('rmkx', {})),
|
||||
('keypad_xmit', ('smkx', {})),
|
||||
('meta_off', ('rmm', {})),
|
||||
('meta_on', ('smm', {})),
|
||||
('orig_pair', ('op', {})),
|
||||
('parm_down_cursor', ('cud', {'nparams': 1})),
|
||||
('parm_left_cursor', ('cub', {'nparams': 1, 'match_grouped': True})),
|
||||
('parm_dch', ('dch', {'nparams': 1})),
|
||||
('parm_delete_line', ('dl', {'nparams': 1})),
|
||||
('parm_ich', ('ich', {'nparams': 1})),
|
||||
('parm_index', ('indn', {'nparams': 1})),
|
||||
('parm_insert_line', ('il', {'nparams': 1})),
|
||||
('parm_right_cursor', ('cuf', {'nparams': 1, 'match_grouped': True})),
|
||||
('parm_rindex', ('rin', {'nparams': 1})),
|
||||
('parm_up_cursor', ('cuu', {'nparams': 1})),
|
||||
('print_screen', ('mc0', {})),
|
||||
('prtr_off', ('mc4', {})),
|
||||
('prtr_on', ('mc5', {})),
|
||||
('reset_1string', ('r1', {})),
|
||||
('reset_2string', ('r2', {})),
|
||||
('reset_3string', ('r3', {})),
|
||||
('restore_cursor', ('rc', {})),
|
||||
('row_address', ('vpa', {'nparams': 1})),
|
||||
('save_cursor', ('sc', {})),
|
||||
('scroll_forward', ('ind', {})),
|
||||
('scroll_reverse', ('rev', {})),
|
||||
('set0_des_seq', ('s0ds', {})),
|
||||
('set1_des_seq', ('s1ds', {})),
|
||||
('set2_des_seq', ('s2ds', {})),
|
||||
('set3_des_seq', ('s3ds', {})),
|
||||
# this 'color' is deceiving, but often matching, and a better match
|
||||
# than set_a_attributes1 or set_a_foreground.
|
||||
('color', ('_foreground_color', {'nparams': 1, 'match_any': True,
|
||||
'numeric': 1})),
|
||||
('set_a_foreground', ('color', {'nparams': 1, 'match_any': True,
|
||||
'numeric': 1})),
|
||||
('set_a_background', ('on_color', {'nparams': 1, 'match_any': True,
|
||||
'numeric': 1})),
|
||||
('set_tab', ('hts', {})),
|
||||
('tab', ('ht', {})),
|
||||
('italic', ('sitm', {})),
|
||||
('no_italic', ('sitm', {})),
|
||||
))
|
||||
|
||||
CAPABILITIES_RAW_MIXIN = {
|
||||
'bell': re.escape('\a'),
|
||||
'carriage_return': re.escape('\r'),
|
||||
'cursor_left': re.escape('\b'),
|
||||
'cursor_report': re.escape('\x1b') + r'\[(\d+)\;(\d+)R',
|
||||
'cursor_right': re.escape('\x1b') + r'\[C',
|
||||
'exit_attribute_mode': re.escape('\x1b') + r'\[m',
|
||||
'parm_left_cursor': re.escape('\x1b') + r'\[(\d+)D',
|
||||
'parm_right_cursor': re.escape('\x1b') + r'\[(\d+)C',
|
||||
'restore_cursor': re.escape(r'\x1b\[u'),
|
||||
'save_cursor': re.escape(r'\x1b\[s'),
|
||||
'scroll_forward': re.escape('\n'),
|
||||
'set0_des_seq': re.escape('\x1b(B'),
|
||||
'tab': re.escape('\t'),
|
||||
}
|
||||
_ANY_NOTESC = '[^' + re.escape('\x1b') + ']*'
|
||||
|
||||
CAPABILITIES_ADDITIVES = {
|
||||
'link': ('link',
|
||||
re.escape('\x1b') + r'\]8;' + _ANY_NOTESC + ';' +
|
||||
_ANY_NOTESC + re.escape('\x1b') + '\\\\'),
|
||||
'color256': ('color', re.escape('\x1b') + r'\[38;5;\d+m'),
|
||||
'on_color256': ('on_color', re.escape('\x1b') + r'\[48;5;\d+m'),
|
||||
'color_rgb': ('color_rgb', re.escape('\x1b') + r'\[38;2;\d+;\d+;\d+m'),
|
||||
'on_color_rgb': ('on_color_rgb', re.escape('\x1b') + r'\[48;2;\d+;\d+;\d+m'),
|
||||
'shift_in': ('', re.escape('\x0f')),
|
||||
'shift_out': ('', re.escape('\x0e')),
|
||||
# sgr(...) outputs strangely, use the basic ANSI/EMCA-48 codes here.
|
||||
'set_a_attributes1': (
|
||||
'sgr', re.escape('\x1b') + r'\[\d+m'),
|
||||
'set_a_attributes2': (
|
||||
'sgr', re.escape('\x1b') + r'\[\d+\;\d+m'),
|
||||
'set_a_attributes3': (
|
||||
'sgr', re.escape('\x1b') + r'\[\d+\;\d+\;\d+m'),
|
||||
'set_a_attributes4': (
|
||||
'sgr', re.escape('\x1b') + r'\[\d+\;\d+\;\d+\;\d+m'),
|
||||
# this helps where xterm's sgr0 includes set0_des_seq, we'd
|
||||
# rather like to also match this immediate substring.
|
||||
'sgr0': ('sgr0', re.escape('\x1b') + r'\[m'),
|
||||
'backspace': ('', re.escape('\b')),
|
||||
'ascii_tab': ('', re.escape('\t')),
|
||||
'clr_eol': ('', re.escape('\x1b[K')),
|
||||
'clr_eol0': ('', re.escape('\x1b[0K')),
|
||||
'clr_bol': ('', re.escape('\x1b[1K')),
|
||||
'clr_eosK': ('', re.escape('\x1b[2K')),
|
||||
}
|
||||
|
||||
CAPABILITIES_CAUSE_MOVEMENT = (
|
||||
'ascii_tab',
|
||||
'backspace',
|
||||
'carriage_return',
|
||||
'clear_screen',
|
||||
'column_address',
|
||||
'cursor_address',
|
||||
'cursor_down',
|
||||
'cursor_home',
|
||||
'cursor_left',
|
||||
'cursor_right',
|
||||
'cursor_up',
|
||||
'enter_fullscreen',
|
||||
'exit_fullscreen',
|
||||
'parm_down_cursor',
|
||||
'parm_left_cursor',
|
||||
'parm_right_cursor',
|
||||
'parm_up_cursor',
|
||||
'restore_cursor',
|
||||
'row_address',
|
||||
'scroll_forward',
|
||||
'tab',
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
# std imports
|
||||
from typing import Any, Dict, Tuple, OrderedDict
|
||||
|
||||
CAPABILITY_DATABASE: OrderedDict[str, Tuple[str, Dict[str, Any]]]
|
||||
CAPABILITIES_RAW_MIXIN: Dict[str, str]
|
||||
CAPABILITIES_ADDITIVES: Dict[str, Tuple[str, str]]
|
||||
CAPABILITIES_CAUSE_MOVEMENT: Tuple[str, ...]
|
|
@ -0,0 +1,258 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Sub-module providing color functions.
|
||||
|
||||
References,
|
||||
|
||||
- https://en.wikipedia.org/wiki/Color_difference
|
||||
- http://www.easyrgb.com/en/math.php
|
||||
- Measuring Colour by R.W.G. Hunt and M.R. Pointer
|
||||
"""
|
||||
|
||||
# std imports
|
||||
from math import cos, exp, sin, sqrt, atan2
|
||||
|
||||
# isort: off
|
||||
try:
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
# lru_cache was added in Python 3.2
|
||||
from backports.functools_lru_cache import lru_cache
|
||||
|
||||
|
||||
def rgb_to_xyz(red, green, blue):
|
||||
"""
|
||||
Convert standard RGB color to XYZ color.
|
||||
|
||||
:arg int red: RGB value of Red.
|
||||
:arg int green: RGB value of Green.
|
||||
:arg int blue: RGB value of Blue.
|
||||
:returns: Tuple (X, Y, Z) representing XYZ color
|
||||
:rtype: tuple
|
||||
|
||||
D65/2° standard illuminant
|
||||
"""
|
||||
rgb = []
|
||||
for val in red, green, blue:
|
||||
val /= 255.0
|
||||
if val > 0.04045:
|
||||
val = pow((val + 0.055) / 1.055, 2.4)
|
||||
else:
|
||||
val /= 12.92
|
||||
val *= 100
|
||||
rgb.append(val)
|
||||
|
||||
red, green, blue = rgb # pylint: disable=unbalanced-tuple-unpacking
|
||||
x_val = red * 0.4124 + green * 0.3576 + blue * 0.1805
|
||||
y_val = red * 0.2126 + green * 0.7152 + blue * 0.0722
|
||||
z_val = red * 0.0193 + green * 0.1192 + blue * 0.9505
|
||||
|
||||
return x_val, y_val, z_val
|
||||
|
||||
|
||||
def xyz_to_lab(x_val, y_val, z_val):
|
||||
"""
|
||||
Convert XYZ color to CIE-Lab color.
|
||||
|
||||
:arg float x_val: XYZ value of X.
|
||||
:arg float y_val: XYZ value of Y.
|
||||
:arg float z_val: XYZ value of Z.
|
||||
:returns: Tuple (L, a, b) representing CIE-Lab color
|
||||
:rtype: tuple
|
||||
|
||||
D65/2° standard illuminant
|
||||
"""
|
||||
xyz = []
|
||||
for val, ref in (x_val, 95.047), (y_val, 100.0), (z_val, 108.883):
|
||||
val /= ref
|
||||
val = pow(val, 1 / 3.0) if val > 0.008856 else 7.787 * val + 16 / 116.0
|
||||
xyz.append(val)
|
||||
|
||||
x_val, y_val, z_val = xyz # pylint: disable=unbalanced-tuple-unpacking
|
||||
cie_l = 116 * y_val - 16
|
||||
cie_a = 500 * (x_val - y_val)
|
||||
cie_b = 200 * (y_val - z_val)
|
||||
|
||||
return cie_l, cie_a, cie_b
|
||||
|
||||
|
||||
@lru_cache(maxsize=256)
|
||||
def rgb_to_lab(red, green, blue):
|
||||
"""
|
||||
Convert RGB color to CIE-Lab color.
|
||||
|
||||
:arg int red: RGB value of Red.
|
||||
:arg int green: RGB value of Green.
|
||||
:arg int blue: RGB value of Blue.
|
||||
:returns: Tuple (L, a, b) representing CIE-Lab color
|
||||
:rtype: tuple
|
||||
|
||||
D65/2° standard illuminant
|
||||
"""
|
||||
return xyz_to_lab(*rgb_to_xyz(red, green, blue))
|
||||
|
||||
|
||||
def dist_rgb(rgb1, rgb2):
|
||||
"""
|
||||
Determine distance between two rgb colors.
|
||||
|
||||
:arg tuple rgb1: RGB color definition
|
||||
:arg tuple rgb2: RGB color definition
|
||||
:returns: Square of the distance between provided colors
|
||||
:rtype: float
|
||||
|
||||
This works by treating RGB colors as coordinates in three dimensional
|
||||
space and finding the closest point within the configured color range
|
||||
using the formula::
|
||||
|
||||
d^2 = (r2 - r1)^2 + (g2 - g1)^2 + (b2 - b1)^2
|
||||
|
||||
For efficiency, the square of the distance is returned
|
||||
which is sufficient for comparisons
|
||||
"""
|
||||
return sum(pow(rgb1[idx] - rgb2[idx], 2) for idx in (0, 1, 2))
|
||||
|
||||
|
||||
def dist_rgb_weighted(rgb1, rgb2):
|
||||
"""
|
||||
Determine the weighted distance between two rgb colors.
|
||||
|
||||
:arg tuple rgb1: RGB color definition
|
||||
:arg tuple rgb2: RGB color definition
|
||||
:returns: Square of the distance between provided colors
|
||||
:rtype: float
|
||||
|
||||
Similar to a standard distance formula, the values are weighted
|
||||
to approximate human perception of color differences
|
||||
|
||||
For efficiency, the square of the distance is returned
|
||||
which is sufficient for comparisons
|
||||
"""
|
||||
red_mean = (rgb1[0] + rgb2[0]) / 2.0
|
||||
|
||||
return ((2 + red_mean / 256) * pow(rgb1[0] - rgb2[0], 2) +
|
||||
4 * pow(rgb1[1] - rgb2[1], 2) +
|
||||
(2 + (255 - red_mean) / 256) * pow(rgb1[2] - rgb2[2], 2))
|
||||
|
||||
|
||||
def dist_cie76(rgb1, rgb2):
|
||||
"""
|
||||
Determine distance between two rgb colors using the CIE94 algorithm.
|
||||
|
||||
:arg tuple rgb1: RGB color definition
|
||||
:arg tuple rgb2: RGB color definition
|
||||
:returns: Square of the distance between provided colors
|
||||
:rtype: float
|
||||
|
||||
For efficiency, the square of the distance is returned
|
||||
which is sufficient for comparisons
|
||||
"""
|
||||
l_1, a_1, b_1 = rgb_to_lab(*rgb1)
|
||||
l_2, a_2, b_2 = rgb_to_lab(*rgb2)
|
||||
return pow(l_1 - l_2, 2) + pow(a_1 - a_2, 2) + pow(b_1 - b_2, 2)
|
||||
|
||||
|
||||
def dist_cie94(rgb1, rgb2):
|
||||
# pylint: disable=too-many-locals
|
||||
"""
|
||||
Determine distance between two rgb colors using the CIE94 algorithm.
|
||||
|
||||
:arg tuple rgb1: RGB color definition
|
||||
:arg tuple rgb2: RGB color definition
|
||||
:returns: Square of the distance between provided colors
|
||||
:rtype: float
|
||||
|
||||
For efficiency, the square of the distance is returned
|
||||
which is sufficient for comparisons
|
||||
"""
|
||||
l_1, a_1, b_1 = rgb_to_lab(*rgb1)
|
||||
l_2, a_2, b_2 = rgb_to_lab(*rgb2)
|
||||
|
||||
s_l = k_l = k_c = k_h = 1
|
||||
k_1 = 0.045
|
||||
k_2 = 0.015
|
||||
|
||||
delta_l = l_1 - l_2
|
||||
delta_a = a_1 - a_2
|
||||
delta_b = b_1 - b_2
|
||||
c_1 = sqrt(a_1 ** 2 + b_1 ** 2)
|
||||
c_2 = sqrt(a_2 ** 2 + b_2 ** 2)
|
||||
delta_c = c_1 - c_2
|
||||
delta_h = sqrt(delta_a ** 2 + delta_b ** 2 + delta_c ** 2)
|
||||
s_c = 1 + k_1 * c_1
|
||||
s_h = 1 + k_2 * c_1
|
||||
|
||||
return ((delta_l / (k_l * s_l)) ** 2 + # pylint: disable=superfluous-parens
|
||||
(delta_c / (k_c * s_c)) ** 2 +
|
||||
(delta_h / (k_h * s_h)) ** 2)
|
||||
|
||||
|
||||
def dist_cie2000(rgb1, rgb2):
|
||||
# pylint: disable=too-many-locals
|
||||
"""
|
||||
Determine distance between two rgb colors using the CIE2000 algorithm.
|
||||
|
||||
:arg tuple rgb1: RGB color definition
|
||||
:arg tuple rgb2: RGB color definition
|
||||
:returns: Square of the distance between provided colors
|
||||
:rtype: float
|
||||
|
||||
For efficiency, the square of the distance is returned
|
||||
which is sufficient for comparisons
|
||||
"""
|
||||
s_l = k_l = k_c = k_h = 1
|
||||
|
||||
l_1, a_1, b_1 = rgb_to_lab(*rgb1)
|
||||
l_2, a_2, b_2 = rgb_to_lab(*rgb2)
|
||||
|
||||
delta_l = l_2 - l_1
|
||||
l_mean = (l_1 + l_2) / 2
|
||||
|
||||
c_1 = sqrt(a_1 ** 2 + b_1 ** 2)
|
||||
c_2 = sqrt(a_2 ** 2 + b_2 ** 2)
|
||||
c_mean = (c_1 + c_2) / 2
|
||||
delta_c = c_1 - c_2
|
||||
|
||||
g_x = sqrt(c_mean ** 7 / (c_mean ** 7 + 25 ** 7))
|
||||
h_1 = atan2(b_1, a_1 + (a_1 / 2) * (1 - g_x)) % 360
|
||||
h_2 = atan2(b_2, a_2 + (a_2 / 2) * (1 - g_x)) % 360
|
||||
|
||||
if 0 in (c_1, c_2):
|
||||
delta_h_prime = 0
|
||||
h_mean = h_1 + h_2
|
||||
else:
|
||||
delta_h_prime = h_2 - h_1
|
||||
if abs(delta_h_prime) <= 180:
|
||||
h_mean = (h_1 + h_2) / 2
|
||||
else:
|
||||
if h_2 <= h_1:
|
||||
delta_h_prime += 360
|
||||
else:
|
||||
delta_h_prime -= 360
|
||||
h_mean = (h_1 + h_2 + 360) / 2 if h_1 + h_2 < 360 else (h_1 + h_2 - 360) / 2
|
||||
|
||||
delta_h = 2 * sqrt(c_1 * c_2) * sin(delta_h_prime / 2)
|
||||
|
||||
t_x = (1 -
|
||||
0.17 * cos(h_mean - 30) +
|
||||
0.24 * cos(2 * h_mean) +
|
||||
0.32 * cos(3 * h_mean + 6) -
|
||||
0.20 * cos(4 * h_mean - 63))
|
||||
|
||||
s_l = 1 + (0.015 * (l_mean - 50) ** 2) / sqrt(20 + (l_mean - 50) ** 2)
|
||||
s_c = 1 + 0.045 * c_mean
|
||||
s_h = 1 + 0.015 * c_mean * t_x
|
||||
r_t = -2 * g_x * sin(abs(60 * exp(-1 * abs((delta_h - 275) / 25) ** 2)))
|
||||
|
||||
delta_l = delta_l / (k_l * s_l)
|
||||
delta_c = delta_c / (k_c * s_c)
|
||||
delta_h = delta_h / (k_h * s_h)
|
||||
|
||||
return delta_l ** 2 + delta_c ** 2 + delta_h ** 2 + r_t * delta_c * delta_h
|
||||
|
||||
|
||||
COLOR_DISTANCE_ALGORITHMS = {'rgb': dist_rgb,
|
||||
'rgb-weighted': dist_rgb_weighted,
|
||||
'cie76': dist_cie76,
|
||||
'cie94': dist_cie94,
|
||||
'cie2000': dist_cie2000}
|
|
@ -0,0 +1,17 @@
|
|||
# std imports
|
||||
from typing import Dict, Tuple, Callable
|
||||
|
||||
_RGB = Tuple[int, int, int]
|
||||
|
||||
def rgb_to_xyz(red: int, green: int, blue: int) -> Tuple[float, float, float]: ...
|
||||
def xyz_to_lab(
|
||||
x_val: float, y_val: float, z_val: float
|
||||
) -> Tuple[float, float, float]: ...
|
||||
def rgb_to_lab(red: int, green: int, blue: int) -> Tuple[float, float, float]: ...
|
||||
def dist_rgb(rgb1: _RGB, rgb2: _RGB) -> float: ...
|
||||
def dist_rgb_weighted(rgb1: _RGB, rgb2: _RGB) -> float: ...
|
||||
def dist_cie76(rgb1: _RGB, rgb2: _RGB) -> float: ...
|
||||
def dist_cie94(rgb1: _RGB, rgb2: _RGB) -> float: ...
|
||||
def dist_cie2000(rgb1: _RGB, rgb2: _RGB) -> float: ...
|
||||
|
||||
COLOR_DISTANCE_ALGORITHMS: Dict[str, Callable[[_RGB, _RGB], float]]
|
|
@ -0,0 +1,973 @@
|
|||
"""
|
||||
Color reference data.
|
||||
|
||||
References,
|
||||
|
||||
- https://github.com/freedesktop/xorg-rgb/blob/master/rgb.txt
|
||||
- https://github.com/ThomasDickey/xterm-snapshots/blob/master/256colres.h
|
||||
- https://github.com/ThomasDickey/xterm-snapshots/blob/master/XTerm-col.ad
|
||||
- https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||
- https://gist.github.com/XVilka/8346728
|
||||
- https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/
|
||||
- http://jdebp.uk/Softwares/nosh/guide/TerminalCapabilities.html
|
||||
"""
|
||||
# std imports
|
||||
import collections
|
||||
|
||||
__all__ = (
|
||||
'CGA_COLORS',
|
||||
'RGBColor',
|
||||
'RGB_256TABLE',
|
||||
'X11_COLORNAMES_TO_RGB',
|
||||
)
|
||||
|
||||
CGA_COLORS = set(
|
||||
('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'))
|
||||
|
||||
|
||||
class RGBColor(collections.namedtuple("RGBColor", ["red", "green", "blue"])):
|
||||
"""Named tuple for an RGB color definition."""
|
||||
|
||||
def __str__(self):
|
||||
return '#{0:02x}{1:02x}{2:02x}'.format(*self)
|
||||
|
||||
|
||||
#: X11 Color names to (XTerm-defined) RGB values from xorg-rgb/rgb.txt
|
||||
X11_COLORNAMES_TO_RGB = {
|
||||
'aliceblue': RGBColor(240, 248, 255),
|
||||
'antiquewhite': RGBColor(250, 235, 215),
|
||||
'antiquewhite1': RGBColor(255, 239, 219),
|
||||
'antiquewhite2': RGBColor(238, 223, 204),
|
||||
'antiquewhite3': RGBColor(205, 192, 176),
|
||||
'antiquewhite4': RGBColor(139, 131, 120),
|
||||
'aqua': RGBColor(0, 255, 255),
|
||||
'aquamarine': RGBColor(127, 255, 212),
|
||||
'aquamarine1': RGBColor(127, 255, 212),
|
||||
'aquamarine2': RGBColor(118, 238, 198),
|
||||
'aquamarine3': RGBColor(102, 205, 170),
|
||||
'aquamarine4': RGBColor(69, 139, 116),
|
||||
'azure': RGBColor(240, 255, 255),
|
||||
'azure1': RGBColor(240, 255, 255),
|
||||
'azure2': RGBColor(224, 238, 238),
|
||||
'azure3': RGBColor(193, 205, 205),
|
||||
'azure4': RGBColor(131, 139, 139),
|
||||
'beige': RGBColor(245, 245, 220),
|
||||
'bisque': RGBColor(255, 228, 196),
|
||||
'bisque1': RGBColor(255, 228, 196),
|
||||
'bisque2': RGBColor(238, 213, 183),
|
||||
'bisque3': RGBColor(205, 183, 158),
|
||||
'bisque4': RGBColor(139, 125, 107),
|
||||
'black': RGBColor(0, 0, 0),
|
||||
'blanchedalmond': RGBColor(255, 235, 205),
|
||||
'blue': RGBColor(0, 0, 255),
|
||||
'blue1': RGBColor(0, 0, 255),
|
||||
'blue2': RGBColor(0, 0, 238),
|
||||
'blue3': RGBColor(0, 0, 205),
|
||||
'blue4': RGBColor(0, 0, 139),
|
||||
'blueviolet': RGBColor(138, 43, 226),
|
||||
'brown': RGBColor(165, 42, 42),
|
||||
'brown1': RGBColor(255, 64, 64),
|
||||
'brown2': RGBColor(238, 59, 59),
|
||||
'brown3': RGBColor(205, 51, 51),
|
||||
'brown4': RGBColor(139, 35, 35),
|
||||
'burlywood': RGBColor(222, 184, 135),
|
||||
'burlywood1': RGBColor(255, 211, 155),
|
||||
'burlywood2': RGBColor(238, 197, 145),
|
||||
'burlywood3': RGBColor(205, 170, 125),
|
||||
'burlywood4': RGBColor(139, 115, 85),
|
||||
'cadetblue': RGBColor(95, 158, 160),
|
||||
'cadetblue1': RGBColor(152, 245, 255),
|
||||
'cadetblue2': RGBColor(142, 229, 238),
|
||||
'cadetblue3': RGBColor(122, 197, 205),
|
||||
'cadetblue4': RGBColor(83, 134, 139),
|
||||
'chartreuse': RGBColor(127, 255, 0),
|
||||
'chartreuse1': RGBColor(127, 255, 0),
|
||||
'chartreuse2': RGBColor(118, 238, 0),
|
||||
'chartreuse3': RGBColor(102, 205, 0),
|
||||
'chartreuse4': RGBColor(69, 139, 0),
|
||||
'chocolate': RGBColor(210, 105, 30),
|
||||
'chocolate1': RGBColor(255, 127, 36),
|
||||
'chocolate2': RGBColor(238, 118, 33),
|
||||
'chocolate3': RGBColor(205, 102, 29),
|
||||
'chocolate4': RGBColor(139, 69, 19),
|
||||
'coral': RGBColor(255, 127, 80),
|
||||
'coral1': RGBColor(255, 114, 86),
|
||||
'coral2': RGBColor(238, 106, 80),
|
||||
'coral3': RGBColor(205, 91, 69),
|
||||
'coral4': RGBColor(139, 62, 47),
|
||||
'cornflowerblue': RGBColor(100, 149, 237),
|
||||
'cornsilk': RGBColor(255, 248, 220),
|
||||
'cornsilk1': RGBColor(255, 248, 220),
|
||||
'cornsilk2': RGBColor(238, 232, 205),
|
||||
'cornsilk3': RGBColor(205, 200, 177),
|
||||
'cornsilk4': RGBColor(139, 136, 120),
|
||||
'crimson': RGBColor(220, 20, 60),
|
||||
'cyan': RGBColor(0, 255, 255),
|
||||
'cyan1': RGBColor(0, 255, 255),
|
||||
'cyan2': RGBColor(0, 238, 238),
|
||||
'cyan3': RGBColor(0, 205, 205),
|
||||
'cyan4': RGBColor(0, 139, 139),
|
||||
'darkblue': RGBColor(0, 0, 139),
|
||||
'darkcyan': RGBColor(0, 139, 139),
|
||||
'darkgoldenrod': RGBColor(184, 134, 11),
|
||||
'darkgoldenrod1': RGBColor(255, 185, 15),
|
||||
'darkgoldenrod2': RGBColor(238, 173, 14),
|
||||
'darkgoldenrod3': RGBColor(205, 149, 12),
|
||||
'darkgoldenrod4': RGBColor(139, 101, 8),
|
||||
'darkgray': RGBColor(169, 169, 169),
|
||||
'darkgreen': RGBColor(0, 100, 0),
|
||||
'darkgrey': RGBColor(169, 169, 169),
|
||||
'darkkhaki': RGBColor(189, 183, 107),
|
||||
'darkmagenta': RGBColor(139, 0, 139),
|
||||
'darkolivegreen': RGBColor(85, 107, 47),
|
||||
'darkolivegreen1': RGBColor(202, 255, 112),
|
||||
'darkolivegreen2': RGBColor(188, 238, 104),
|
||||
'darkolivegreen3': RGBColor(162, 205, 90),
|
||||
'darkolivegreen4': RGBColor(110, 139, 61),
|
||||
'darkorange': RGBColor(255, 140, 0),
|
||||
'darkorange1': RGBColor(255, 127, 0),
|
||||
'darkorange2': RGBColor(238, 118, 0),
|
||||
'darkorange3': RGBColor(205, 102, 0),
|
||||
'darkorange4': RGBColor(139, 69, 0),
|
||||
'darkorchid': RGBColor(153, 50, 204),
|
||||
'darkorchid1': RGBColor(191, 62, 255),
|
||||
'darkorchid2': RGBColor(178, 58, 238),
|
||||
'darkorchid3': RGBColor(154, 50, 205),
|
||||
'darkorchid4': RGBColor(104, 34, 139),
|
||||
'darkred': RGBColor(139, 0, 0),
|
||||
'darksalmon': RGBColor(233, 150, 122),
|
||||
'darkseagreen': RGBColor(143, 188, 143),
|
||||
'darkseagreen1': RGBColor(193, 255, 193),
|
||||
'darkseagreen2': RGBColor(180, 238, 180),
|
||||
'darkseagreen3': RGBColor(155, 205, 155),
|
||||
'darkseagreen4': RGBColor(105, 139, 105),
|
||||
'darkslateblue': RGBColor(72, 61, 139),
|
||||
'darkslategray': RGBColor(47, 79, 79),
|
||||
'darkslategray1': RGBColor(151, 255, 255),
|
||||
'darkslategray2': RGBColor(141, 238, 238),
|
||||
'darkslategray3': RGBColor(121, 205, 205),
|
||||
'darkslategray4': RGBColor(82, 139, 139),
|
||||
'darkslategrey': RGBColor(47, 79, 79),
|
||||
'darkturquoise': RGBColor(0, 206, 209),
|
||||
'darkviolet': RGBColor(148, 0, 211),
|
||||
'deeppink': RGBColor(255, 20, 147),
|
||||
'deeppink1': RGBColor(255, 20, 147),
|
||||
'deeppink2': RGBColor(238, 18, 137),
|
||||
'deeppink3': RGBColor(205, 16, 118),
|
||||
'deeppink4': RGBColor(139, 10, 80),
|
||||
'deepskyblue': RGBColor(0, 191, 255),
|
||||
'deepskyblue1': RGBColor(0, 191, 255),
|
||||
'deepskyblue2': RGBColor(0, 178, 238),
|
||||
'deepskyblue3': RGBColor(0, 154, 205),
|
||||
'deepskyblue4': RGBColor(0, 104, 139),
|
||||
'dimgray': RGBColor(105, 105, 105),
|
||||
'dimgrey': RGBColor(105, 105, 105),
|
||||
'dodgerblue': RGBColor(30, 144, 255),
|
||||
'dodgerblue1': RGBColor(30, 144, 255),
|
||||
'dodgerblue2': RGBColor(28, 134, 238),
|
||||
'dodgerblue3': RGBColor(24, 116, 205),
|
||||
'dodgerblue4': RGBColor(16, 78, 139),
|
||||
'firebrick': RGBColor(178, 34, 34),
|
||||
'firebrick1': RGBColor(255, 48, 48),
|
||||
'firebrick2': RGBColor(238, 44, 44),
|
||||
'firebrick3': RGBColor(205, 38, 38),
|
||||
'firebrick4': RGBColor(139, 26, 26),
|
||||
'floralwhite': RGBColor(255, 250, 240),
|
||||
'forestgreen': RGBColor(34, 139, 34),
|
||||
'fuchsia': RGBColor(255, 0, 255),
|
||||
'gainsboro': RGBColor(220, 220, 220),
|
||||
'ghostwhite': RGBColor(248, 248, 255),
|
||||
'gold': RGBColor(255, 215, 0),
|
||||
'gold1': RGBColor(255, 215, 0),
|
||||
'gold2': RGBColor(238, 201, 0),
|
||||
'gold3': RGBColor(205, 173, 0),
|
||||
'gold4': RGBColor(139, 117, 0),
|
||||
'goldenrod': RGBColor(218, 165, 32),
|
||||
'goldenrod1': RGBColor(255, 193, 37),
|
||||
'goldenrod2': RGBColor(238, 180, 34),
|
||||
'goldenrod3': RGBColor(205, 155, 29),
|
||||
'goldenrod4': RGBColor(139, 105, 20),
|
||||
'gray': RGBColor(190, 190, 190),
|
||||
'gray0': RGBColor(0, 0, 0),
|
||||
'gray1': RGBColor(3, 3, 3),
|
||||
'gray10': RGBColor(26, 26, 26),
|
||||
'gray100': RGBColor(255, 255, 255),
|
||||
'gray11': RGBColor(28, 28, 28),
|
||||
'gray12': RGBColor(31, 31, 31),
|
||||
'gray13': RGBColor(33, 33, 33),
|
||||
'gray14': RGBColor(36, 36, 36),
|
||||
'gray15': RGBColor(38, 38, 38),
|
||||
'gray16': RGBColor(41, 41, 41),
|
||||
'gray17': RGBColor(43, 43, 43),
|
||||
'gray18': RGBColor(46, 46, 46),
|
||||
'gray19': RGBColor(48, 48, 48),
|
||||
'gray2': RGBColor(5, 5, 5),
|
||||
'gray20': RGBColor(51, 51, 51),
|
||||
'gray21': RGBColor(54, 54, 54),
|
||||
'gray22': RGBColor(56, 56, 56),
|
||||
'gray23': RGBColor(59, 59, 59),
|
||||
'gray24': RGBColor(61, 61, 61),
|
||||
'gray25': RGBColor(64, 64, 64),
|
||||
'gray26': RGBColor(66, 66, 66),
|
||||
'gray27': RGBColor(69, 69, 69),
|
||||
'gray28': RGBColor(71, 71, 71),
|
||||
'gray29': RGBColor(74, 74, 74),
|
||||
'gray3': RGBColor(8, 8, 8),
|
||||
'gray30': RGBColor(77, 77, 77),
|
||||
'gray31': RGBColor(79, 79, 79),
|
||||
'gray32': RGBColor(82, 82, 82),
|
||||
'gray33': RGBColor(84, 84, 84),
|
||||
'gray34': RGBColor(87, 87, 87),
|
||||
'gray35': RGBColor(89, 89, 89),
|
||||
'gray36': RGBColor(92, 92, 92),
|
||||
'gray37': RGBColor(94, 94, 94),
|
||||
'gray38': RGBColor(97, 97, 97),
|
||||
'gray39': RGBColor(99, 99, 99),
|
||||
'gray4': RGBColor(10, 10, 10),
|
||||
'gray40': RGBColor(102, 102, 102),
|
||||
'gray41': RGBColor(105, 105, 105),
|
||||
'gray42': RGBColor(107, 107, 107),
|
||||
'gray43': RGBColor(110, 110, 110),
|
||||
'gray44': RGBColor(112, 112, 112),
|
||||
'gray45': RGBColor(115, 115, 115),
|
||||
'gray46': RGBColor(117, 117, 117),
|
||||
'gray47': RGBColor(120, 120, 120),
|
||||
'gray48': RGBColor(122, 122, 122),
|
||||
'gray49': RGBColor(125, 125, 125),
|
||||
'gray5': RGBColor(13, 13, 13),
|
||||
'gray50': RGBColor(127, 127, 127),
|
||||
'gray51': RGBColor(130, 130, 130),
|
||||
'gray52': RGBColor(133, 133, 133),
|
||||
'gray53': RGBColor(135, 135, 135),
|
||||
'gray54': RGBColor(138, 138, 138),
|
||||
'gray55': RGBColor(140, 140, 140),
|
||||
'gray56': RGBColor(143, 143, 143),
|
||||
'gray57': RGBColor(145, 145, 145),
|
||||
'gray58': RGBColor(148, 148, 148),
|
||||
'gray59': RGBColor(150, 150, 150),
|
||||
'gray6': RGBColor(15, 15, 15),
|
||||
'gray60': RGBColor(153, 153, 153),
|
||||
'gray61': RGBColor(156, 156, 156),
|
||||
'gray62': RGBColor(158, 158, 158),
|
||||
'gray63': RGBColor(161, 161, 161),
|
||||
'gray64': RGBColor(163, 163, 163),
|
||||
'gray65': RGBColor(166, 166, 166),
|
||||
'gray66': RGBColor(168, 168, 168),
|
||||
'gray67': RGBColor(171, 171, 171),
|
||||
'gray68': RGBColor(173, 173, 173),
|
||||
'gray69': RGBColor(176, 176, 176),
|
||||
'gray7': RGBColor(18, 18, 18),
|
||||
'gray70': RGBColor(179, 179, 179),
|
||||
'gray71': RGBColor(181, 181, 181),
|
||||
'gray72': RGBColor(184, 184, 184),
|
||||
'gray73': RGBColor(186, 186, 186),
|
||||
'gray74': RGBColor(189, 189, 189),
|
||||
'gray75': RGBColor(191, 191, 191),
|
||||
'gray76': RGBColor(194, 194, 194),
|
||||
'gray77': RGBColor(196, 196, 196),
|
||||
'gray78': RGBColor(199, 199, 199),
|
||||
'gray79': RGBColor(201, 201, 201),
|
||||
'gray8': RGBColor(20, 20, 20),
|
||||
'gray80': RGBColor(204, 204, 204),
|
||||
'gray81': RGBColor(207, 207, 207),
|
||||
'gray82': RGBColor(209, 209, 209),
|
||||
'gray83': RGBColor(212, 212, 212),
|
||||
'gray84': RGBColor(214, 214, 214),
|
||||
'gray85': RGBColor(217, 217, 217),
|
||||
'gray86': RGBColor(219, 219, 219),
|
||||
'gray87': RGBColor(222, 222, 222),
|
||||
'gray88': RGBColor(224, 224, 224),
|
||||
'gray89': RGBColor(227, 227, 227),
|
||||
'gray9': RGBColor(23, 23, 23),
|
||||
'gray90': RGBColor(229, 229, 229),
|
||||
'gray91': RGBColor(232, 232, 232),
|
||||
'gray92': RGBColor(235, 235, 235),
|
||||
'gray93': RGBColor(237, 237, 237),
|
||||
'gray94': RGBColor(240, 240, 240),
|
||||
'gray95': RGBColor(242, 242, 242),
|
||||
'gray96': RGBColor(245, 245, 245),
|
||||
'gray97': RGBColor(247, 247, 247),
|
||||
'gray98': RGBColor(250, 250, 250),
|
||||
'gray99': RGBColor(252, 252, 252),
|
||||
'green': RGBColor(0, 255, 0),
|
||||
'green1': RGBColor(0, 255, 0),
|
||||
'green2': RGBColor(0, 238, 0),
|
||||
'green3': RGBColor(0, 205, 0),
|
||||
'green4': RGBColor(0, 139, 0),
|
||||
'greenyellow': RGBColor(173, 255, 47),
|
||||
'grey': RGBColor(190, 190, 190),
|
||||
'grey0': RGBColor(0, 0, 0),
|
||||
'grey1': RGBColor(3, 3, 3),
|
||||
'grey10': RGBColor(26, 26, 26),
|
||||
'grey100': RGBColor(255, 255, 255),
|
||||
'grey11': RGBColor(28, 28, 28),
|
||||
'grey12': RGBColor(31, 31, 31),
|
||||
'grey13': RGBColor(33, 33, 33),
|
||||
'grey14': RGBColor(36, 36, 36),
|
||||
'grey15': RGBColor(38, 38, 38),
|
||||
'grey16': RGBColor(41, 41, 41),
|
||||
'grey17': RGBColor(43, 43, 43),
|
||||
'grey18': RGBColor(46, 46, 46),
|
||||
'grey19': RGBColor(48, 48, 48),
|
||||
'grey2': RGBColor(5, 5, 5),
|
||||
'grey20': RGBColor(51, 51, 51),
|
||||
'grey21': RGBColor(54, 54, 54),
|
||||
'grey22': RGBColor(56, 56, 56),
|
||||
'grey23': RGBColor(59, 59, 59),
|
||||
'grey24': RGBColor(61, 61, 61),
|
||||
'grey25': RGBColor(64, 64, 64),
|
||||
'grey26': RGBColor(66, 66, 66),
|
||||
'grey27': RGBColor(69, 69, 69),
|
||||
'grey28': RGBColor(71, 71, 71),
|
||||
'grey29': RGBColor(74, 74, 74),
|
||||
'grey3': RGBColor(8, 8, 8),
|
||||
'grey30': RGBColor(77, 77, 77),
|
||||
'grey31': RGBColor(79, 79, 79),
|
||||
'grey32': RGBColor(82, 82, 82),
|
||||
'grey33': RGBColor(84, 84, 84),
|
||||
'grey34': RGBColor(87, 87, 87),
|
||||
'grey35': RGBColor(89, 89, 89),
|
||||
'grey36': RGBColor(92, 92, 92),
|
||||
'grey37': RGBColor(94, 94, 94),
|
||||
'grey38': RGBColor(97, 97, 97),
|
||||
'grey39': RGBColor(99, 99, 99),
|
||||
'grey4': RGBColor(10, 10, 10),
|
||||
'grey40': RGBColor(102, 102, 102),
|
||||
'grey41': RGBColor(105, 105, 105),
|
||||
'grey42': RGBColor(107, 107, 107),
|
||||
'grey43': RGBColor(110, 110, 110),
|
||||
'grey44': RGBColor(112, 112, 112),
|
||||
'grey45': RGBColor(115, 115, 115),
|
||||
'grey46': RGBColor(117, 117, 117),
|
||||
'grey47': RGBColor(120, 120, 120),
|
||||
'grey48': RGBColor(122, 122, 122),
|
||||
'grey49': RGBColor(125, 125, 125),
|
||||
'grey5': RGBColor(13, 13, 13),
|
||||
'grey50': RGBColor(127, 127, 127),
|
||||
'grey51': RGBColor(130, 130, 130),
|
||||
'grey52': RGBColor(133, 133, 133),
|
||||
'grey53': RGBColor(135, 135, 135),
|
||||
'grey54': RGBColor(138, 138, 138),
|
||||
'grey55': RGBColor(140, 140, 140),
|
||||
'grey56': RGBColor(143, 143, 143),
|
||||
'grey57': RGBColor(145, 145, 145),
|
||||
'grey58': RGBColor(148, 148, 148),
|
||||
'grey59': RGBColor(150, 150, 150),
|
||||
'grey6': RGBColor(15, 15, 15),
|
||||
'grey60': RGBColor(153, 153, 153),
|
||||
'grey61': RGBColor(156, 156, 156),
|
||||
'grey62': RGBColor(158, 158, 158),
|
||||
'grey63': RGBColor(161, 161, 161),
|
||||
'grey64': RGBColor(163, 163, 163),
|
||||
'grey65': RGBColor(166, 166, 166),
|
||||
'grey66': RGBColor(168, 168, 168),
|
||||
'grey67': RGBColor(171, 171, 171),
|
||||
'grey68': RGBColor(173, 173, 173),
|
||||
'grey69': RGBColor(176, 176, 176),
|
||||
'grey7': RGBColor(18, 18, 18),
|
||||
'grey70': RGBColor(179, 179, 179),
|
||||
'grey71': RGBColor(181, 181, 181),
|
||||
'grey72': RGBColor(184, 184, 184),
|
||||
'grey73': RGBColor(186, 186, 186),
|
||||
'grey74': RGBColor(189, 189, 189),
|
||||
'grey75': RGBColor(191, 191, 191),
|
||||
'grey76': RGBColor(194, 194, 194),
|
||||
'grey77': RGBColor(196, 196, 196),
|
||||
'grey78': RGBColor(199, 199, 199),
|
||||
'grey79': RGBColor(201, 201, 201),
|
||||
'grey8': RGBColor(20, 20, 20),
|
||||
'grey80': RGBColor(204, 204, 204),
|
||||
'grey81': RGBColor(207, 207, 207),
|
||||
'grey82': RGBColor(209, 209, 209),
|
||||
'grey83': RGBColor(212, 212, 212),
|
||||
'grey84': RGBColor(214, 214, 214),
|
||||
'grey85': RGBColor(217, 217, 217),
|
||||
'grey86': RGBColor(219, 219, 219),
|
||||
'grey87': RGBColor(222, 222, 222),
|
||||
'grey88': RGBColor(224, 224, 224),
|
||||
'grey89': RGBColor(227, 227, 227),
|
||||
'grey9': RGBColor(23, 23, 23),
|
||||
'grey90': RGBColor(229, 229, 229),
|
||||
'grey91': RGBColor(232, 232, 232),
|
||||
'grey92': RGBColor(235, 235, 235),
|
||||
'grey93': RGBColor(237, 237, 237),
|
||||
'grey94': RGBColor(240, 240, 240),
|
||||
'grey95': RGBColor(242, 242, 242),
|
||||
'grey96': RGBColor(245, 245, 245),
|
||||
'grey97': RGBColor(247, 247, 247),
|
||||
'grey98': RGBColor(250, 250, 250),
|
||||
'grey99': RGBColor(252, 252, 252),
|
||||
'honeydew': RGBColor(240, 255, 240),
|
||||
'honeydew1': RGBColor(240, 255, 240),
|
||||
'honeydew2': RGBColor(224, 238, 224),
|
||||
'honeydew3': RGBColor(193, 205, 193),
|
||||
'honeydew4': RGBColor(131, 139, 131),
|
||||
'hotpink': RGBColor(255, 105, 180),
|
||||
'hotpink1': RGBColor(255, 110, 180),
|
||||
'hotpink2': RGBColor(238, 106, 167),
|
||||
'hotpink3': RGBColor(205, 96, 144),
|
||||
'hotpink4': RGBColor(139, 58, 98),
|
||||
'indianred': RGBColor(205, 92, 92),
|
||||
'indianred1': RGBColor(255, 106, 106),
|
||||
'indianred2': RGBColor(238, 99, 99),
|
||||
'indianred3': RGBColor(205, 85, 85),
|
||||
'indianred4': RGBColor(139, 58, 58),
|
||||
'indigo': RGBColor(75, 0, 130),
|
||||
'ivory': RGBColor(255, 255, 240),
|
||||
'ivory1': RGBColor(255, 255, 240),
|
||||
'ivory2': RGBColor(238, 238, 224),
|
||||
'ivory3': RGBColor(205, 205, 193),
|
||||
'ivory4': RGBColor(139, 139, 131),
|
||||
'khaki': RGBColor(240, 230, 140),
|
||||
'khaki1': RGBColor(255, 246, 143),
|
||||
'khaki2': RGBColor(238, 230, 133),
|
||||
'khaki3': RGBColor(205, 198, 115),
|
||||
'khaki4': RGBColor(139, 134, 78),
|
||||
'lavender': RGBColor(230, 230, 250),
|
||||
'lavenderblush': RGBColor(255, 240, 245),
|
||||
'lavenderblush1': RGBColor(255, 240, 245),
|
||||
'lavenderblush2': RGBColor(238, 224, 229),
|
||||
'lavenderblush3': RGBColor(205, 193, 197),
|
||||
'lavenderblush4': RGBColor(139, 131, 134),
|
||||
'lawngreen': RGBColor(124, 252, 0),
|
||||
'lemonchiffon': RGBColor(255, 250, 205),
|
||||
'lemonchiffon1': RGBColor(255, 250, 205),
|
||||
'lemonchiffon2': RGBColor(238, 233, 191),
|
||||
'lemonchiffon3': RGBColor(205, 201, 165),
|
||||
'lemonchiffon4': RGBColor(139, 137, 112),
|
||||
'lightblue': RGBColor(173, 216, 230),
|
||||
'lightblue1': RGBColor(191, 239, 255),
|
||||
'lightblue2': RGBColor(178, 223, 238),
|
||||
'lightblue3': RGBColor(154, 192, 205),
|
||||
'lightblue4': RGBColor(104, 131, 139),
|
||||
'lightcoral': RGBColor(240, 128, 128),
|
||||
'lightcyan': RGBColor(224, 255, 255),
|
||||
'lightcyan1': RGBColor(224, 255, 255),
|
||||
'lightcyan2': RGBColor(209, 238, 238),
|
||||
'lightcyan3': RGBColor(180, 205, 205),
|
||||
'lightcyan4': RGBColor(122, 139, 139),
|
||||
'lightgoldenrod': RGBColor(238, 221, 130),
|
||||
'lightgoldenrod1': RGBColor(255, 236, 139),
|
||||
'lightgoldenrod2': RGBColor(238, 220, 130),
|
||||
'lightgoldenrod3': RGBColor(205, 190, 112),
|
||||
'lightgoldenrod4': RGBColor(139, 129, 76),
|
||||
'lightgoldenrodyellow': RGBColor(250, 250, 210),
|
||||
'lightgray': RGBColor(211, 211, 211),
|
||||
'lightgreen': RGBColor(144, 238, 144),
|
||||
'lightgrey': RGBColor(211, 211, 211),
|
||||
'lightpink': RGBColor(255, 182, 193),
|
||||
'lightpink1': RGBColor(255, 174, 185),
|
||||
'lightpink2': RGBColor(238, 162, 173),
|
||||
'lightpink3': RGBColor(205, 140, 149),
|
||||
'lightpink4': RGBColor(139, 95, 101),
|
||||
'lightsalmon': RGBColor(255, 160, 122),
|
||||
'lightsalmon1': RGBColor(255, 160, 122),
|
||||
'lightsalmon2': RGBColor(238, 149, 114),
|
||||
'lightsalmon3': RGBColor(205, 129, 98),
|
||||
'lightsalmon4': RGBColor(139, 87, 66),
|
||||
'lightseagreen': RGBColor(32, 178, 170),
|
||||
'lightskyblue': RGBColor(135, 206, 250),
|
||||
'lightskyblue1': RGBColor(176, 226, 255),
|
||||
'lightskyblue2': RGBColor(164, 211, 238),
|
||||
'lightskyblue3': RGBColor(141, 182, 205),
|
||||
'lightskyblue4': RGBColor(96, 123, 139),
|
||||
'lightslateblue': RGBColor(132, 112, 255),
|
||||
'lightslategray': RGBColor(119, 136, 153),
|
||||
'lightslategrey': RGBColor(119, 136, 153),
|
||||
'lightsteelblue': RGBColor(176, 196, 222),
|
||||
'lightsteelblue1': RGBColor(202, 225, 255),
|
||||
'lightsteelblue2': RGBColor(188, 210, 238),
|
||||
'lightsteelblue3': RGBColor(162, 181, 205),
|
||||
'lightsteelblue4': RGBColor(110, 123, 139),
|
||||
'lightyellow': RGBColor(255, 255, 224),
|
||||
'lightyellow1': RGBColor(255, 255, 224),
|
||||
'lightyellow2': RGBColor(238, 238, 209),
|
||||
'lightyellow3': RGBColor(205, 205, 180),
|
||||
'lightyellow4': RGBColor(139, 139, 122),
|
||||
'lime': RGBColor(0, 255, 0),
|
||||
'limegreen': RGBColor(50, 205, 50),
|
||||
'linen': RGBColor(250, 240, 230),
|
||||
'magenta': RGBColor(255, 0, 255),
|
||||
'magenta1': RGBColor(255, 0, 255),
|
||||
'magenta2': RGBColor(238, 0, 238),
|
||||
'magenta3': RGBColor(205, 0, 205),
|
||||
'magenta4': RGBColor(139, 0, 139),
|
||||
'maroon': RGBColor(176, 48, 96),
|
||||
'maroon1': RGBColor(255, 52, 179),
|
||||
'maroon2': RGBColor(238, 48, 167),
|
||||
'maroon3': RGBColor(205, 41, 144),
|
||||
'maroon4': RGBColor(139, 28, 98),
|
||||
'mediumaquamarine': RGBColor(102, 205, 170),
|
||||
'mediumblue': RGBColor(0, 0, 205),
|
||||
'mediumorchid': RGBColor(186, 85, 211),
|
||||
'mediumorchid1': RGBColor(224, 102, 255),
|
||||
'mediumorchid2': RGBColor(209, 95, 238),
|
||||
'mediumorchid3': RGBColor(180, 82, 205),
|
||||
'mediumorchid4': RGBColor(122, 55, 139),
|
||||
'mediumpurple': RGBColor(147, 112, 219),
|
||||
'mediumpurple1': RGBColor(171, 130, 255),
|
||||
'mediumpurple2': RGBColor(159, 121, 238),
|
||||
'mediumpurple3': RGBColor(137, 104, 205),
|
||||
'mediumpurple4': RGBColor(93, 71, 139),
|
||||
'mediumseagreen': RGBColor(60, 179, 113),
|
||||
'mediumslateblue': RGBColor(123, 104, 238),
|
||||
'mediumspringgreen': RGBColor(0, 250, 154),
|
||||
'mediumturquoise': RGBColor(72, 209, 204),
|
||||
'mediumvioletred': RGBColor(199, 21, 133),
|
||||
'midnightblue': RGBColor(25, 25, 112),
|
||||
'mintcream': RGBColor(245, 255, 250),
|
||||
'mistyrose': RGBColor(255, 228, 225),
|
||||
'mistyrose1': RGBColor(255, 228, 225),
|
||||
'mistyrose2': RGBColor(238, 213, 210),
|
||||
'mistyrose3': RGBColor(205, 183, 181),
|
||||
'mistyrose4': RGBColor(139, 125, 123),
|
||||
'moccasin': RGBColor(255, 228, 181),
|
||||
'navajowhite': RGBColor(255, 222, 173),
|
||||
'navajowhite1': RGBColor(255, 222, 173),
|
||||
'navajowhite2': RGBColor(238, 207, 161),
|
||||
'navajowhite3': RGBColor(205, 179, 139),
|
||||
'navajowhite4': RGBColor(139, 121, 94),
|
||||
'navy': RGBColor(0, 0, 128),
|
||||
'navyblue': RGBColor(0, 0, 128),
|
||||
'oldlace': RGBColor(253, 245, 230),
|
||||
'olive': RGBColor(128, 128, 0),
|
||||
'olivedrab': RGBColor(107, 142, 35),
|
||||
'olivedrab1': RGBColor(192, 255, 62),
|
||||
'olivedrab2': RGBColor(179, 238, 58),
|
||||
'olivedrab3': RGBColor(154, 205, 50),
|
||||
'olivedrab4': RGBColor(105, 139, 34),
|
||||
'orange': RGBColor(255, 165, 0),
|
||||
'orange1': RGBColor(255, 165, 0),
|
||||
'orange2': RGBColor(238, 154, 0),
|
||||
'orange3': RGBColor(205, 133, 0),
|
||||
'orange4': RGBColor(139, 90, 0),
|
||||
'orangered': RGBColor(255, 69, 0),
|
||||
'orangered1': RGBColor(255, 69, 0),
|
||||
'orangered2': RGBColor(238, 64, 0),
|
||||
'orangered3': RGBColor(205, 55, 0),
|
||||
'orangered4': RGBColor(139, 37, 0),
|
||||
'orchid': RGBColor(218, 112, 214),
|
||||
'orchid1': RGBColor(255, 131, 250),
|
||||
'orchid2': RGBColor(238, 122, 233),
|
||||
'orchid3': RGBColor(205, 105, 201),
|
||||
'orchid4': RGBColor(139, 71, 137),
|
||||
'palegoldenrod': RGBColor(238, 232, 170),
|
||||
'palegreen': RGBColor(152, 251, 152),
|
||||
'palegreen1': RGBColor(154, 255, 154),
|
||||
'palegreen2': RGBColor(144, 238, 144),
|
||||
'palegreen3': RGBColor(124, 205, 124),
|
||||
'palegreen4': RGBColor(84, 139, 84),
|
||||
'paleturquoise': RGBColor(175, 238, 238),
|
||||
'paleturquoise1': RGBColor(187, 255, 255),
|
||||
'paleturquoise2': RGBColor(174, 238, 238),
|
||||
'paleturquoise3': RGBColor(150, 205, 205),
|
||||
'paleturquoise4': RGBColor(102, 139, 139),
|
||||
'palevioletred': RGBColor(219, 112, 147),
|
||||
'palevioletred1': RGBColor(255, 130, 171),
|
||||
'palevioletred2': RGBColor(238, 121, 159),
|
||||
'palevioletred3': RGBColor(205, 104, 137),
|
||||
'palevioletred4': RGBColor(139, 71, 93),
|
||||
'papayawhip': RGBColor(255, 239, 213),
|
||||
'peachpuff': RGBColor(255, 218, 185),
|
||||
'peachpuff1': RGBColor(255, 218, 185),
|
||||
'peachpuff2': RGBColor(238, 203, 173),
|
||||
'peachpuff3': RGBColor(205, 175, 149),
|
||||
'peachpuff4': RGBColor(139, 119, 101),
|
||||
'peru': RGBColor(205, 133, 63),
|
||||
'pink': RGBColor(255, 192, 203),
|
||||
'pink1': RGBColor(255, 181, 197),
|
||||
'pink2': RGBColor(238, 169, 184),
|
||||
'pink3': RGBColor(205, 145, 158),
|
||||
'pink4': RGBColor(139, 99, 108),
|
||||
'plum': RGBColor(221, 160, 221),
|
||||
'plum1': RGBColor(255, 187, 255),
|
||||
'plum2': RGBColor(238, 174, 238),
|
||||
'plum3': RGBColor(205, 150, 205),
|
||||
'plum4': RGBColor(139, 102, 139),
|
||||
'powderblue': RGBColor(176, 224, 230),
|
||||
'purple': RGBColor(160, 32, 240),
|
||||
'purple1': RGBColor(155, 48, 255),
|
||||
'purple2': RGBColor(145, 44, 238),
|
||||
'purple3': RGBColor(125, 38, 205),
|
||||
'purple4': RGBColor(85, 26, 139),
|
||||
'rebeccapurple': RGBColor(102, 51, 153),
|
||||
'red': RGBColor(255, 0, 0),
|
||||
'red1': RGBColor(255, 0, 0),
|
||||
'red2': RGBColor(238, 0, 0),
|
||||
'red3': RGBColor(205, 0, 0),
|
||||
'red4': RGBColor(139, 0, 0),
|
||||
'rosybrown': RGBColor(188, 143, 143),
|
||||
'rosybrown1': RGBColor(255, 193, 193),
|
||||
'rosybrown2': RGBColor(238, 180, 180),
|
||||
'rosybrown3': RGBColor(205, 155, 155),
|
||||
'rosybrown4': RGBColor(139, 105, 105),
|
||||
'royalblue': RGBColor(65, 105, 225),
|
||||
'royalblue1': RGBColor(72, 118, 255),
|
||||
'royalblue2': RGBColor(67, 110, 238),
|
||||
'royalblue3': RGBColor(58, 95, 205),
|
||||
'royalblue4': RGBColor(39, 64, 139),
|
||||
'saddlebrown': RGBColor(139, 69, 19),
|
||||
'salmon': RGBColor(250, 128, 114),
|
||||
'salmon1': RGBColor(255, 140, 105),
|
||||
'salmon2': RGBColor(238, 130, 98),
|
||||
'salmon3': RGBColor(205, 112, 84),
|
||||
'salmon4': RGBColor(139, 76, 57),
|
||||
'sandybrown': RGBColor(244, 164, 96),
|
||||
'seagreen': RGBColor(46, 139, 87),
|
||||
'seagreen1': RGBColor(84, 255, 159),
|
||||
'seagreen2': RGBColor(78, 238, 148),
|
||||
'seagreen3': RGBColor(67, 205, 128),
|
||||
'seagreen4': RGBColor(46, 139, 87),
|
||||
'seashell': RGBColor(255, 245, 238),
|
||||
'seashell1': RGBColor(255, 245, 238),
|
||||
'seashell2': RGBColor(238, 229, 222),
|
||||
'seashell3': RGBColor(205, 197, 191),
|
||||
'seashell4': RGBColor(139, 134, 130),
|
||||
'sienna': RGBColor(160, 82, 45),
|
||||
'sienna1': RGBColor(255, 130, 71),
|
||||
'sienna2': RGBColor(238, 121, 66),
|
||||
'sienna3': RGBColor(205, 104, 57),
|
||||
'sienna4': RGBColor(139, 71, 38),
|
||||
'silver': RGBColor(192, 192, 192),
|
||||
'skyblue': RGBColor(135, 206, 235),
|
||||
'skyblue1': RGBColor(135, 206, 255),
|
||||
'skyblue2': RGBColor(126, 192, 238),
|
||||
'skyblue3': RGBColor(108, 166, 205),
|
||||
'skyblue4': RGBColor(74, 112, 139),
|
||||
'slateblue': RGBColor(106, 90, 205),
|
||||
'slateblue1': RGBColor(131, 111, 255),
|
||||
'slateblue2': RGBColor(122, 103, 238),
|
||||
'slateblue3': RGBColor(105, 89, 205),
|
||||
'slateblue4': RGBColor(71, 60, 139),
|
||||
'slategray': RGBColor(112, 128, 144),
|
||||
'slategray1': RGBColor(198, 226, 255),
|
||||
'slategray2': RGBColor(185, 211, 238),
|
||||
'slategray3': RGBColor(159, 182, 205),
|
||||
'slategray4': RGBColor(108, 123, 139),
|
||||
'slategrey': RGBColor(112, 128, 144),
|
||||
'snow': RGBColor(255, 250, 250),
|
||||
'snow1': RGBColor(255, 250, 250),
|
||||
'snow2': RGBColor(238, 233, 233),
|
||||
'snow3': RGBColor(205, 201, 201),
|
||||
'snow4': RGBColor(139, 137, 137),
|
||||
'springgreen': RGBColor(0, 255, 127),
|
||||
'springgreen1': RGBColor(0, 255, 127),
|
||||
'springgreen2': RGBColor(0, 238, 118),
|
||||
'springgreen3': RGBColor(0, 205, 102),
|
||||
'springgreen4': RGBColor(0, 139, 69),
|
||||
'steelblue': RGBColor(70, 130, 180),
|
||||
'steelblue1': RGBColor(99, 184, 255),
|
||||
'steelblue2': RGBColor(92, 172, 238),
|
||||
'steelblue3': RGBColor(79, 148, 205),
|
||||
'steelblue4': RGBColor(54, 100, 139),
|
||||
'tan': RGBColor(210, 180, 140),
|
||||
'tan1': RGBColor(255, 165, 79),
|
||||
'tan2': RGBColor(238, 154, 73),
|
||||
'tan3': RGBColor(205, 133, 63),
|
||||
'tan4': RGBColor(139, 90, 43),
|
||||
'teal': RGBColor(0, 128, 128),
|
||||
'thistle': RGBColor(216, 191, 216),
|
||||
'thistle1': RGBColor(255, 225, 255),
|
||||
'thistle2': RGBColor(238, 210, 238),
|
||||
'thistle3': RGBColor(205, 181, 205),
|
||||
'thistle4': RGBColor(139, 123, 139),
|
||||
'tomato': RGBColor(255, 99, 71),
|
||||
'tomato1': RGBColor(255, 99, 71),
|
||||
'tomato2': RGBColor(238, 92, 66),
|
||||
'tomato3': RGBColor(205, 79, 57),
|
||||
'tomato4': RGBColor(139, 54, 38),
|
||||
'turquoise': RGBColor(64, 224, 208),
|
||||
'turquoise1': RGBColor(0, 245, 255),
|
||||
'turquoise2': RGBColor(0, 229, 238),
|
||||
'turquoise3': RGBColor(0, 197, 205),
|
||||
'turquoise4': RGBColor(0, 134, 139),
|
||||
'violet': RGBColor(238, 130, 238),
|
||||
'violetred': RGBColor(208, 32, 144),
|
||||
'violetred1': RGBColor(255, 62, 150),
|
||||
'violetred2': RGBColor(238, 58, 140),
|
||||
'violetred3': RGBColor(205, 50, 120),
|
||||
'violetred4': RGBColor(139, 34, 82),
|
||||
'webgray': RGBColor(128, 128, 128),
|
||||
'webgreen': RGBColor(0, 128, 0),
|
||||
'webgrey': RGBColor(128, 128, 128),
|
||||
'webmaroon': RGBColor(128, 0, 0),
|
||||
'webpurple': RGBColor(128, 0, 128),
|
||||
'wheat': RGBColor(245, 222, 179),
|
||||
'wheat1': RGBColor(255, 231, 186),
|
||||
'wheat2': RGBColor(238, 216, 174),
|
||||
'wheat3': RGBColor(205, 186, 150),
|
||||
'wheat4': RGBColor(139, 126, 102),
|
||||
'white': RGBColor(255, 255, 255),
|
||||
'whitesmoke': RGBColor(245, 245, 245),
|
||||
'x11gray': RGBColor(190, 190, 190),
|
||||
'x11green': RGBColor(0, 255, 0),
|
||||
'x11grey': RGBColor(190, 190, 190),
|
||||
'x11maroon': RGBColor(176, 48, 96),
|
||||
'x11purple': RGBColor(160, 32, 240),
|
||||
'yellow': RGBColor(255, 255, 0),
|
||||
'yellow1': RGBColor(255, 255, 0),
|
||||
'yellow2': RGBColor(238, 238, 0),
|
||||
'yellow3': RGBColor(205, 205, 0),
|
||||
'yellow4': RGBColor(139, 139, 0),
|
||||
'yellowgreen': RGBColor(154, 205, 50)
|
||||
}
|
||||
|
||||
#: Curses color indices of 8, 16, and 256-color terminals
|
||||
RGB_256TABLE = (
|
||||
RGBColor(0, 0, 0),
|
||||
RGBColor(205, 0, 0),
|
||||
RGBColor(0, 205, 0),
|
||||
RGBColor(205, 205, 0),
|
||||
RGBColor(0, 0, 238),
|
||||
RGBColor(205, 0, 205),
|
||||
RGBColor(0, 205, 205),
|
||||
RGBColor(229, 229, 229),
|
||||
RGBColor(127, 127, 127),
|
||||
RGBColor(255, 0, 0),
|
||||
RGBColor(0, 255, 0),
|
||||
RGBColor(255, 255, 0),
|
||||
RGBColor(92, 92, 255),
|
||||
RGBColor(255, 0, 255),
|
||||
RGBColor(0, 255, 255),
|
||||
RGBColor(255, 255, 255),
|
||||
RGBColor(0, 0, 0),
|
||||
RGBColor(0, 0, 95),
|
||||
RGBColor(0, 0, 135),
|
||||
RGBColor(0, 0, 175),
|
||||
RGBColor(0, 0, 215),
|
||||
RGBColor(0, 0, 255),
|
||||
RGBColor(0, 95, 0),
|
||||
RGBColor(0, 95, 95),
|
||||
RGBColor(0, 95, 135),
|
||||
RGBColor(0, 95, 175),
|
||||
RGBColor(0, 95, 215),
|
||||
RGBColor(0, 95, 255),
|
||||
RGBColor(0, 135, 0),
|
||||
RGBColor(0, 135, 95),
|
||||
RGBColor(0, 135, 135),
|
||||
RGBColor(0, 135, 175),
|
||||
RGBColor(0, 135, 215),
|
||||
RGBColor(0, 135, 255),
|
||||
RGBColor(0, 175, 0),
|
||||
RGBColor(0, 175, 95),
|
||||
RGBColor(0, 175, 135),
|
||||
RGBColor(0, 175, 175),
|
||||
RGBColor(0, 175, 215),
|
||||
RGBColor(0, 175, 255),
|
||||
RGBColor(0, 215, 0),
|
||||
RGBColor(0, 215, 95),
|
||||
RGBColor(0, 215, 135),
|
||||
RGBColor(0, 215, 175),
|
||||
RGBColor(0, 215, 215),
|
||||
RGBColor(0, 215, 255),
|
||||
RGBColor(0, 255, 0),
|
||||
RGBColor(0, 255, 95),
|
||||
RGBColor(0, 255, 135),
|
||||
RGBColor(0, 255, 175),
|
||||
RGBColor(0, 255, 215),
|
||||
RGBColor(0, 255, 255),
|
||||
RGBColor(95, 0, 0),
|
||||
RGBColor(95, 0, 95),
|
||||
RGBColor(95, 0, 135),
|
||||
RGBColor(95, 0, 175),
|
||||
RGBColor(95, 0, 215),
|
||||
RGBColor(95, 0, 255),
|
||||
RGBColor(95, 95, 0),
|
||||
RGBColor(95, 95, 95),
|
||||
RGBColor(95, 95, 135),
|
||||
RGBColor(95, 95, 175),
|
||||
RGBColor(95, 95, 215),
|
||||
RGBColor(95, 95, 255),
|
||||
RGBColor(95, 135, 0),
|
||||
RGBColor(95, 135, 95),
|
||||
RGBColor(95, 135, 135),
|
||||
RGBColor(95, 135, 175),
|
||||
RGBColor(95, 135, 215),
|
||||
RGBColor(95, 135, 255),
|
||||
RGBColor(95, 175, 0),
|
||||
RGBColor(95, 175, 95),
|
||||
RGBColor(95, 175, 135),
|
||||
RGBColor(95, 175, 175),
|
||||
RGBColor(95, 175, 215),
|
||||
RGBColor(95, 175, 255),
|
||||
RGBColor(95, 215, 0),
|
||||
RGBColor(95, 215, 95),
|
||||
RGBColor(95, 215, 135),
|
||||
RGBColor(95, 215, 175),
|
||||
RGBColor(95, 215, 215),
|
||||
RGBColor(95, 215, 255),
|
||||
RGBColor(95, 255, 0),
|
||||
RGBColor(95, 255, 95),
|
||||
RGBColor(95, 255, 135),
|
||||
RGBColor(95, 255, 175),
|
||||
RGBColor(95, 255, 215),
|
||||
RGBColor(95, 255, 255),
|
||||
RGBColor(135, 0, 0),
|
||||
RGBColor(135, 0, 95),
|
||||
RGBColor(135, 0, 135),
|
||||
RGBColor(135, 0, 175),
|
||||
RGBColor(135, 0, 215),
|
||||
RGBColor(135, 0, 255),
|
||||
RGBColor(135, 95, 0),
|
||||
RGBColor(135, 95, 95),
|
||||
RGBColor(135, 95, 135),
|
||||
RGBColor(135, 95, 175),
|
||||
RGBColor(135, 95, 215),
|
||||
RGBColor(135, 95, 255),
|
||||
RGBColor(135, 135, 0),
|
||||
RGBColor(135, 135, 95),
|
||||
RGBColor(135, 135, 135),
|
||||
RGBColor(135, 135, 175),
|
||||
RGBColor(135, 135, 215),
|
||||
RGBColor(135, 135, 255),
|
||||
RGBColor(135, 175, 0),
|
||||
RGBColor(135, 175, 95),
|
||||
RGBColor(135, 175, 135),
|
||||
RGBColor(135, 175, 175),
|
||||
RGBColor(135, 175, 215),
|
||||
RGBColor(135, 175, 255),
|
||||
RGBColor(135, 215, 0),
|
||||
RGBColor(135, 215, 95),
|
||||
RGBColor(135, 215, 135),
|
||||
RGBColor(135, 215, 175),
|
||||
RGBColor(135, 215, 215),
|
||||
RGBColor(135, 215, 255),
|
||||
RGBColor(135, 255, 0),
|
||||
RGBColor(135, 255, 95),
|
||||
RGBColor(135, 255, 135),
|
||||
RGBColor(135, 255, 175),
|
||||
RGBColor(135, 255, 215),
|
||||
RGBColor(135, 255, 255),
|
||||
RGBColor(175, 0, 0),
|
||||
RGBColor(175, 0, 95),
|
||||
RGBColor(175, 0, 135),
|
||||
RGBColor(175, 0, 175),
|
||||
RGBColor(175, 0, 215),
|
||||
RGBColor(175, 0, 255),
|
||||
RGBColor(175, 95, 0),
|
||||
RGBColor(175, 95, 95),
|
||||
RGBColor(175, 95, 135),
|
||||
RGBColor(175, 95, 175),
|
||||
RGBColor(175, 95, 215),
|
||||
RGBColor(175, 95, 255),
|
||||
RGBColor(175, 135, 0),
|
||||
RGBColor(175, 135, 95),
|
||||
RGBColor(175, 135, 135),
|
||||
RGBColor(175, 135, 175),
|
||||
RGBColor(175, 135, 215),
|
||||
RGBColor(175, 135, 255),
|
||||
RGBColor(175, 175, 0),
|
||||
RGBColor(175, 175, 95),
|
||||
RGBColor(175, 175, 135),
|
||||
RGBColor(175, 175, 175),
|
||||
RGBColor(175, 175, 215),
|
||||
RGBColor(175, 175, 255),
|
||||
RGBColor(175, 215, 0),
|
||||
RGBColor(175, 215, 95),
|
||||
RGBColor(175, 215, 135),
|
||||
RGBColor(175, 215, 175),
|
||||
RGBColor(175, 215, 215),
|
||||
RGBColor(175, 215, 255),
|
||||
RGBColor(175, 255, 0),
|
||||
RGBColor(175, 255, 95),
|
||||
RGBColor(175, 255, 135),
|
||||
RGBColor(175, 255, 175),
|
||||
RGBColor(175, 255, 215),
|
||||
RGBColor(175, 255, 255),
|
||||
RGBColor(215, 0, 0),
|
||||
RGBColor(215, 0, 95),
|
||||
RGBColor(215, 0, 135),
|
||||
RGBColor(215, 0, 175),
|
||||
RGBColor(215, 0, 215),
|
||||
RGBColor(215, 0, 255),
|
||||
RGBColor(215, 95, 0),
|
||||
RGBColor(215, 95, 95),
|
||||
RGBColor(215, 95, 135),
|
||||
RGBColor(215, 95, 175),
|
||||
RGBColor(215, 95, 215),
|
||||
RGBColor(215, 95, 255),
|
||||
RGBColor(215, 135, 0),
|
||||
RGBColor(215, 135, 95),
|
||||
RGBColor(215, 135, 135),
|
||||
RGBColor(215, 135, 175),
|
||||
RGBColor(215, 135, 215),
|
||||
RGBColor(215, 135, 255),
|
||||
RGBColor(215, 175, 0),
|
||||
RGBColor(215, 175, 95),
|
||||
RGBColor(215, 175, 135),
|
||||
RGBColor(215, 175, 175),
|
||||
RGBColor(215, 175, 215),
|
||||
RGBColor(215, 175, 255),
|
||||
RGBColor(215, 215, 0),
|
||||
RGBColor(215, 215, 95),
|
||||
RGBColor(215, 215, 135),
|
||||
RGBColor(215, 215, 175),
|
||||
RGBColor(215, 215, 215),
|
||||
RGBColor(215, 215, 255),
|
||||
RGBColor(215, 255, 0),
|
||||
RGBColor(215, 255, 95),
|
||||
RGBColor(215, 255, 135),
|
||||
RGBColor(215, 255, 175),
|
||||
RGBColor(215, 255, 215),
|
||||
RGBColor(215, 255, 255),
|
||||
RGBColor(255, 0, 0),
|
||||
RGBColor(255, 0, 135),
|
||||
RGBColor(255, 0, 95),
|
||||
RGBColor(255, 0, 175),
|
||||
RGBColor(255, 0, 215),
|
||||
RGBColor(255, 0, 255),
|
||||
RGBColor(255, 95, 0),
|
||||
RGBColor(255, 95, 95),
|
||||
RGBColor(255, 95, 135),
|
||||
RGBColor(255, 95, 175),
|
||||
RGBColor(255, 95, 215),
|
||||
RGBColor(255, 95, 255),
|
||||
RGBColor(255, 135, 0),
|
||||
RGBColor(255, 135, 95),
|
||||
RGBColor(255, 135, 135),
|
||||
RGBColor(255, 135, 175),
|
||||
RGBColor(255, 135, 215),
|
||||
RGBColor(255, 135, 255),
|
||||
RGBColor(255, 175, 0),
|
||||
RGBColor(255, 175, 95),
|
||||
RGBColor(255, 175, 135),
|
||||
RGBColor(255, 175, 175),
|
||||
RGBColor(255, 175, 215),
|
||||
RGBColor(255, 175, 255),
|
||||
RGBColor(255, 215, 0),
|
||||
RGBColor(255, 215, 95),
|
||||
RGBColor(255, 215, 135),
|
||||
RGBColor(255, 215, 175),
|
||||
RGBColor(255, 215, 215),
|
||||
RGBColor(255, 215, 255),
|
||||
RGBColor(255, 255, 0),
|
||||
RGBColor(255, 255, 95),
|
||||
RGBColor(255, 255, 135),
|
||||
RGBColor(255, 255, 175),
|
||||
RGBColor(255, 255, 215),
|
||||
RGBColor(255, 255, 255),
|
||||
RGBColor(8, 8, 8),
|
||||
RGBColor(18, 18, 18),
|
||||
RGBColor(28, 28, 28),
|
||||
RGBColor(38, 38, 38),
|
||||
RGBColor(48, 48, 48),
|
||||
RGBColor(58, 58, 58),
|
||||
RGBColor(68, 68, 68),
|
||||
RGBColor(78, 78, 78),
|
||||
RGBColor(88, 88, 88),
|
||||
RGBColor(98, 98, 98),
|
||||
RGBColor(108, 108, 108),
|
||||
RGBColor(118, 118, 118),
|
||||
RGBColor(128, 128, 128),
|
||||
RGBColor(138, 138, 138),
|
||||
RGBColor(148, 148, 148),
|
||||
RGBColor(158, 158, 158),
|
||||
RGBColor(168, 168, 168),
|
||||
RGBColor(178, 178, 178),
|
||||
RGBColor(188, 188, 188),
|
||||
RGBColor(198, 198, 198),
|
||||
RGBColor(208, 208, 208),
|
||||
RGBColor(218, 218, 218),
|
||||
RGBColor(228, 228, 228),
|
||||
RGBColor(238, 238, 238),
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
# std imports
|
||||
from typing import Set, Dict, Tuple, NamedTuple
|
||||
|
||||
CGA_COLORS: Set[str]
|
||||
|
||||
class RGBColor(NamedTuple):
|
||||
red: int
|
||||
green: int
|
||||
blue: int
|
||||
|
||||
X11_COLORNAMES_TO_RGB: Dict[str, RGBColor]
|
||||
RGB_256TABLE: Tuple[RGBColor, ...]
|
|
@ -0,0 +1,498 @@
|
|||
"""Sub-module providing sequence-formatting functions."""
|
||||
# std imports
|
||||
import platform
|
||||
|
||||
# 3rd party
|
||||
import six
|
||||
|
||||
# local
|
||||
from blessed.colorspace import CGA_COLORS, X11_COLORNAMES_TO_RGB
|
||||
|
||||
# isort: off
|
||||
# curses
|
||||
if platform.system() == 'Windows':
|
||||
import jinxed as curses # pylint: disable=import-error
|
||||
else:
|
||||
import curses
|
||||
|
||||
|
||||
def _make_colors():
|
||||
"""
|
||||
Return set of valid colors and their derivatives.
|
||||
|
||||
:rtype: set
|
||||
:returns: Color names with prefixes
|
||||
"""
|
||||
colors = set()
|
||||
# basic CGA foreground color, background, high intensity, and bold
|
||||
# background ('iCE colors' in my day).
|
||||
for cga_color in CGA_COLORS:
|
||||
colors.add(cga_color)
|
||||
colors.add('on_' + cga_color)
|
||||
colors.add('bright_' + cga_color)
|
||||
colors.add('on_bright_' + cga_color)
|
||||
|
||||
# foreground and background VGA color
|
||||
for vga_color in X11_COLORNAMES_TO_RGB:
|
||||
colors.add(vga_color)
|
||||
colors.add('on_' + vga_color)
|
||||
return colors
|
||||
|
||||
|
||||
#: Valid colors and their background (on), bright, and bright-background
|
||||
#: derivatives.
|
||||
COLORS = _make_colors()
|
||||
|
||||
#: Attributes that may be compounded with colors, by underscore, such as
|
||||
#: 'reverse_indigo'.
|
||||
COMPOUNDABLES = set('bold underline reverse blink italic standout'.split())
|
||||
|
||||
|
||||
class ParameterizingString(six.text_type):
|
||||
r"""
|
||||
A Unicode string which can be called as a parameterizing termcap.
|
||||
|
||||
For example::
|
||||
|
||||
>>> from blessed import Terminal
|
||||
>>> term = Terminal()
|
||||
>>> color = ParameterizingString(term.color, term.normal, 'color')
|
||||
>>> color(9)('color #9')
|
||||
u'\x1b[91mcolor #9\x1b(B\x1b[m'
|
||||
"""
|
||||
|
||||
def __new__(cls, cap, normal=u'', name=u'<not specified>'):
|
||||
# pylint: disable = missing-return-doc, missing-return-type-doc
|
||||
"""
|
||||
Class constructor accepting 3 positional arguments.
|
||||
|
||||
:arg str cap: parameterized string suitable for curses.tparm()
|
||||
:arg str normal: terminating sequence for this capability (optional).
|
||||
:arg str name: name of this terminal capability (optional).
|
||||
"""
|
||||
new = six.text_type.__new__(cls, cap)
|
||||
new._normal = normal
|
||||
new._name = name
|
||||
return new
|
||||
|
||||
def __call__(self, *args):
|
||||
"""
|
||||
Returning :class:`FormattingString` instance for given parameters.
|
||||
|
||||
Return evaluated terminal capability (self), receiving arguments
|
||||
``*args``, followed by the terminating sequence (self.normal) into
|
||||
a :class:`FormattingString` capable of being called.
|
||||
|
||||
:raises TypeError: Mismatch between capability and arguments
|
||||
:raises curses.error: :func:`curses.tparm` raised an exception
|
||||
:rtype: :class:`FormattingString` or :class:`NullCallableString`
|
||||
:returns: Callable string for given parameters
|
||||
"""
|
||||
try:
|
||||
# Re-encode the cap, because tparm() takes a bytestring in Python
|
||||
# 3. However, appear to be a plain Unicode string otherwise so
|
||||
# concats work.
|
||||
attr = curses.tparm(self.encode('latin1'), *args).decode('latin1')
|
||||
return FormattingString(attr, self._normal)
|
||||
except TypeError as err:
|
||||
# If the first non-int (i.e. incorrect) arg was a string, suggest
|
||||
# something intelligent:
|
||||
if args and isinstance(args[0], six.string_types):
|
||||
raise TypeError(
|
||||
"Unknown terminal capability, %r, or, TypeError "
|
||||
"for arguments %r: %s" % (self._name, args, err))
|
||||
# Somebody passed a non-string; I don't feel confident
|
||||
# guessing what they were trying to do.
|
||||
raise
|
||||
except curses.error as err:
|
||||
# ignore 'tparm() returned NULL', you won't get any styling,
|
||||
# even if does_styling is True. This happens on win32 platforms
|
||||
# with http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses installed
|
||||
if "tparm() returned NULL" not in six.text_type(err):
|
||||
raise
|
||||
return NullCallableString()
|
||||
|
||||
|
||||
class ParameterizingProxyString(six.text_type):
|
||||
r"""
|
||||
A Unicode string which can be called to proxy missing termcap entries.
|
||||
|
||||
This class supports the function :func:`get_proxy_string`, and mirrors
|
||||
the behavior of :class:`ParameterizingString`, except that instead of
|
||||
a capability name, receives a format string, and callable to filter the
|
||||
given positional ``*args`` of :meth:`ParameterizingProxyString.__call__`
|
||||
into a terminal sequence.
|
||||
|
||||
For example::
|
||||
|
||||
>>> from blessed import Terminal
|
||||
>>> term = Terminal('screen')
|
||||
>>> hpa = ParameterizingString(term.hpa, term.normal, 'hpa')
|
||||
>>> hpa(9)
|
||||
u''
|
||||
>>> fmt = u'\x1b[{0}G'
|
||||
>>> fmt_arg = lambda *arg: (arg[0] + 1,)
|
||||
>>> hpa = ParameterizingProxyString((fmt, fmt_arg), term.normal, 'hpa')
|
||||
>>> hpa(9)
|
||||
u'\x1b[10G'
|
||||
"""
|
||||
|
||||
def __new__(cls, fmt_pair, normal=u'', name=u'<not specified>'):
|
||||
# pylint: disable = missing-return-doc, missing-return-type-doc
|
||||
"""
|
||||
Class constructor accepting 4 positional arguments.
|
||||
|
||||
:arg tuple fmt_pair: Two element tuple containing:
|
||||
- format string suitable for displaying terminal sequences
|
||||
- callable suitable for receiving __call__ arguments for formatting string
|
||||
:arg str normal: terminating sequence for this capability (optional).
|
||||
:arg str name: name of this terminal capability (optional).
|
||||
"""
|
||||
assert isinstance(fmt_pair, tuple), fmt_pair
|
||||
assert callable(fmt_pair[1]), fmt_pair[1]
|
||||
new = six.text_type.__new__(cls, fmt_pair[0])
|
||||
new._fmt_args = fmt_pair[1]
|
||||
new._normal = normal
|
||||
new._name = name
|
||||
return new
|
||||
|
||||
def __call__(self, *args):
|
||||
"""
|
||||
Returning :class:`FormattingString` instance for given parameters.
|
||||
|
||||
Arguments are determined by the capability. For example, ``hpa``
|
||||
(move_x) receives only a single integer, whereas ``cup`` (move)
|
||||
receives two integers. See documentation in terminfo(5) for the
|
||||
given capability.
|
||||
|
||||
:rtype: FormattingString
|
||||
:returns: Callable string for given parameters
|
||||
"""
|
||||
return FormattingString(self.format(*self._fmt_args(*args)),
|
||||
self._normal)
|
||||
|
||||
|
||||
class FormattingString(six.text_type):
|
||||
r"""
|
||||
A Unicode string which doubles as a callable.
|
||||
|
||||
This is used for terminal attributes, so that it may be used both
|
||||
directly, or as a callable. When used directly, it simply emits
|
||||
the given terminal sequence. When used as a callable, it wraps the
|
||||
given (string) argument with the 2nd argument used by the class
|
||||
constructor::
|
||||
|
||||
>>> from blessed import Terminal
|
||||
>>> term = Terminal()
|
||||
>>> style = FormattingString(term.bright_blue, term.normal)
|
||||
>>> print(repr(style))
|
||||
u'\x1b[94m'
|
||||
>>> style('Big Blue')
|
||||
u'\x1b[94mBig Blue\x1b(B\x1b[m'
|
||||
"""
|
||||
|
||||
def __new__(cls, sequence, normal=u''):
|
||||
# pylint: disable = missing-return-doc, missing-return-type-doc
|
||||
"""
|
||||
Class constructor accepting 2 positional arguments.
|
||||
|
||||
:arg str sequence: terminal attribute sequence.
|
||||
:arg str normal: terminating sequence for this attribute (optional).
|
||||
"""
|
||||
new = six.text_type.__new__(cls, sequence)
|
||||
new._normal = normal
|
||||
return new
|
||||
|
||||
def __call__(self, *args):
|
||||
"""
|
||||
Return ``text`` joined by ``sequence`` and ``normal``.
|
||||
|
||||
:raises TypeError: Not a string type
|
||||
:rtype: str
|
||||
:returns: Arguments wrapped in sequence and normal
|
||||
"""
|
||||
# Jim Allman brings us this convenience of allowing existing
|
||||
# unicode strings to be joined as a call parameter to a formatting
|
||||
# string result, allowing nestation:
|
||||
#
|
||||
# >>> t.red('This is ', t.bold('extremely'), ' dangerous!')
|
||||
for idx, ucs_part in enumerate(args):
|
||||
if not isinstance(ucs_part, six.string_types):
|
||||
expected_types = ', '.join(_type.__name__ for _type in six.string_types)
|
||||
raise TypeError(
|
||||
"TypeError for FormattingString argument, "
|
||||
"%r, at position %s: expected type %s, "
|
||||
"got %s" % (ucs_part, idx, expected_types,
|
||||
type(ucs_part).__name__))
|
||||
postfix = u''
|
||||
if self and self._normal:
|
||||
postfix = self._normal
|
||||
_refresh = self._normal + self
|
||||
args = [_refresh.join(ucs_part.split(self._normal))
|
||||
for ucs_part in args]
|
||||
|
||||
return self + u''.join(args) + postfix
|
||||
|
||||
|
||||
class FormattingOtherString(six.text_type):
|
||||
r"""
|
||||
A Unicode string which doubles as a callable for another sequence when called.
|
||||
|
||||
This is used for the :meth:`~.Terminal.move_up`, ``down``, ``left``, and ``right()``
|
||||
family of functions::
|
||||
|
||||
>>> from blessed import Terminal
|
||||
>>> term = Terminal()
|
||||
>>> move_right = FormattingOtherString(term.cuf1, term.cuf)
|
||||
>>> print(repr(move_right))
|
||||
u'\x1b[C'
|
||||
>>> print(repr(move_right(666)))
|
||||
u'\x1b[666C'
|
||||
>>> print(repr(move_right()))
|
||||
u'\x1b[C'
|
||||
"""
|
||||
|
||||
def __new__(cls, direct, target):
|
||||
# pylint: disable = missing-return-doc, missing-return-type-doc
|
||||
"""
|
||||
Class constructor accepting 2 positional arguments.
|
||||
|
||||
:arg str direct: capability name for direct formatting, eg ``('x' + term.right)``.
|
||||
:arg str target: capability name for callable, eg ``('x' + term.right(99))``.
|
||||
"""
|
||||
new = six.text_type.__new__(cls, direct)
|
||||
new._callable = target
|
||||
return new
|
||||
|
||||
def __getnewargs__(self):
|
||||
# return arguments used for the __new__ method upon unpickling.
|
||||
return six.text_type.__new__(six.text_type, self), self._callable
|
||||
|
||||
def __call__(self, *args):
|
||||
"""Return ``text`` by ``target``."""
|
||||
if args:
|
||||
return self._callable(*args)
|
||||
return self
|
||||
|
||||
|
||||
class NullCallableString(six.text_type):
|
||||
"""
|
||||
A dummy callable Unicode alternative to :class:`FormattingString`.
|
||||
|
||||
This is used for colors on terminals that do not support colors, it is just a basic form of
|
||||
unicode that may also act as a callable.
|
||||
"""
|
||||
|
||||
def __new__(cls):
|
||||
"""Class constructor."""
|
||||
return six.text_type.__new__(cls, u'')
|
||||
|
||||
def __call__(self, *args):
|
||||
"""
|
||||
Allow empty string to be callable, returning given string, if any.
|
||||
|
||||
When called with an int as the first arg, return an empty Unicode. An
|
||||
int is a good hint that I am a :class:`ParameterizingString`, as there
|
||||
are only about half a dozen string-returning capabilities listed in
|
||||
terminfo(5) which accept non-int arguments, they are seldom used.
|
||||
|
||||
When called with a non-int as the first arg (no no args at all), return
|
||||
the first arg, acting in place of :class:`FormattingString` without
|
||||
any attributes.
|
||||
"""
|
||||
if not args or isinstance(args[0], int):
|
||||
# As a NullCallableString, even when provided with a parameter,
|
||||
# such as t.color(5), we must also still be callable, fe:
|
||||
#
|
||||
# >>> t.color(5)('shmoo')
|
||||
#
|
||||
# is actually simplified result of NullCallable()() on terminals
|
||||
# without color support, so turtles all the way down: we return
|
||||
# another instance.
|
||||
return NullCallableString()
|
||||
return u''.join(args)
|
||||
|
||||
|
||||
def get_proxy_string(term, attr):
|
||||
"""
|
||||
Proxy and return callable string for proxied attributes.
|
||||
|
||||
:arg Terminal term: :class:`~.Terminal` instance.
|
||||
:arg str attr: terminal capability name that may be proxied.
|
||||
:rtype: None or :class:`ParameterizingProxyString`.
|
||||
:returns: :class:`ParameterizingProxyString` for some attributes
|
||||
of some terminal types that support it, where the terminfo(5)
|
||||
database would otherwise come up empty, such as ``move_x``
|
||||
attribute for ``term.kind`` of ``screen``. Otherwise, None.
|
||||
"""
|
||||
# normalize 'screen-256color', or 'ansi.sys' to its basic names
|
||||
term_kind = next(iter(_kind for _kind in ('screen', 'ansi',)
|
||||
if term.kind.startswith(_kind)), term)
|
||||
_proxy_table = { # pragma: no cover
|
||||
'screen': {
|
||||
# proxy move_x/move_y for 'screen' terminal type, used by tmux(1).
|
||||
'hpa': ParameterizingProxyString(
|
||||
(u'\x1b[{0}G', lambda *arg: (arg[0] + 1,)), term.normal, attr),
|
||||
'vpa': ParameterizingProxyString(
|
||||
(u'\x1b[{0}d', lambda *arg: (arg[0] + 1,)), term.normal, attr),
|
||||
},
|
||||
'ansi': {
|
||||
# proxy show/hide cursor for 'ansi' terminal type. There is some
|
||||
# demand for a richly working ANSI terminal type for some reason.
|
||||
'civis': ParameterizingProxyString(
|
||||
(u'\x1b[?25l', lambda *arg: ()), term.normal, attr),
|
||||
'cnorm': ParameterizingProxyString(
|
||||
(u'\x1b[?25h', lambda *arg: ()), term.normal, attr),
|
||||
'hpa': ParameterizingProxyString(
|
||||
(u'\x1b[{0}G', lambda *arg: (arg[0] + 1,)), term.normal, attr),
|
||||
'vpa': ParameterizingProxyString(
|
||||
(u'\x1b[{0}d', lambda *arg: (arg[0] + 1,)), term.normal, attr),
|
||||
'sc': '\x1b[s',
|
||||
'rc': '\x1b[u',
|
||||
}
|
||||
}
|
||||
return _proxy_table.get(term_kind, {}).get(attr, None)
|
||||
|
||||
|
||||
def split_compound(compound):
|
||||
"""
|
||||
Split compound formating string into segments.
|
||||
|
||||
>>> split_compound('bold_underline_bright_blue_on_red')
|
||||
['bold', 'underline', 'bright_blue', 'on_red']
|
||||
|
||||
:arg str compound: a string that may contain compounds, separated by
|
||||
underline (``_``).
|
||||
:rtype: list
|
||||
:returns: List of formating string segments
|
||||
"""
|
||||
merged_segs = []
|
||||
# These occur only as prefixes, so they can always be merged:
|
||||
mergeable_prefixes = ['on', 'bright', 'on_bright']
|
||||
for segment in compound.split('_'):
|
||||
if merged_segs and merged_segs[-1] in mergeable_prefixes:
|
||||
merged_segs[-1] += '_' + segment
|
||||
else:
|
||||
merged_segs.append(segment)
|
||||
return merged_segs
|
||||
|
||||
|
||||
def resolve_capability(term, attr):
|
||||
"""
|
||||
Resolve a raw terminal capability using :func:`tigetstr`.
|
||||
|
||||
:arg Terminal term: :class:`~.Terminal` instance.
|
||||
:arg str attr: terminal capability name.
|
||||
:returns: string of the given terminal capability named by ``attr``,
|
||||
which may be empty (u'') if not found or not supported by the
|
||||
given :attr:`~.Terminal.kind`.
|
||||
:rtype: str
|
||||
"""
|
||||
if not term.does_styling:
|
||||
return u''
|
||||
val = curses.tigetstr(term._sugar.get(attr, attr)) # pylint: disable=protected-access
|
||||
# Decode sequences as latin1, as they are always 8-bit bytes, so when
|
||||
# b'\xff' is returned, this is decoded as u'\xff'.
|
||||
return u'' if val is None else val.decode('latin1')
|
||||
|
||||
|
||||
def resolve_color(term, color):
|
||||
"""
|
||||
Resolve a simple color name to a callable capability.
|
||||
|
||||
This function supports :func:`resolve_attribute`.
|
||||
|
||||
:arg Terminal term: :class:`~.Terminal` instance.
|
||||
:arg str color: any string found in set :const:`COLORS`.
|
||||
:returns: a string class instance which emits the terminal sequence
|
||||
for the given color, and may be used as a callable to wrap the
|
||||
given string with such sequence.
|
||||
:returns: :class:`NullCallableString` when
|
||||
:attr:`~.Terminal.number_of_colors` is 0,
|
||||
otherwise :class:`FormattingString`.
|
||||
:rtype: :class:`NullCallableString` or :class:`FormattingString`
|
||||
"""
|
||||
# pylint: disable=protected-access
|
||||
if term.number_of_colors == 0:
|
||||
return NullCallableString()
|
||||
|
||||
# fg/bg capabilities terminals that support 0-256+ colors.
|
||||
vga_color_cap = (term._background_color if 'on_' in color else
|
||||
term._foreground_color)
|
||||
|
||||
base_color = color.rsplit('_', 1)[-1]
|
||||
if base_color in CGA_COLORS:
|
||||
# curses constants go up to only 7, so add an offset to get at the
|
||||
# bright colors at 8-15:
|
||||
offset = 8 if 'bright_' in color else 0
|
||||
base_color = color.rsplit('_', 1)[-1]
|
||||
attr = 'COLOR_%s' % (base_color.upper(),)
|
||||
fmt_attr = vga_color_cap(getattr(curses, attr) + offset)
|
||||
return FormattingString(fmt_attr, term.normal)
|
||||
|
||||
assert base_color in X11_COLORNAMES_TO_RGB, (
|
||||
'color not known', base_color)
|
||||
rgb = X11_COLORNAMES_TO_RGB[base_color]
|
||||
|
||||
# downconvert X11 colors to CGA, EGA, or VGA color spaces
|
||||
if term.number_of_colors <= 256:
|
||||
fmt_attr = vga_color_cap(term.rgb_downconvert(*rgb))
|
||||
return FormattingString(fmt_attr, term.normal)
|
||||
|
||||
# Modern 24-bit color terminals are written pretty basically. The
|
||||
# foreground and background sequences are:
|
||||
# - ^[38;2;<r>;<g>;<b>m
|
||||
# - ^[48;2;<r>;<g>;<b>m
|
||||
fgbg_seq = ('48' if 'on_' in color else '38')
|
||||
assert term.number_of_colors == 1 << 24
|
||||
fmt_attr = u'\x1b[' + fgbg_seq + ';2;{0};{1};{2}m'
|
||||
return FormattingString(fmt_attr.format(*rgb), term.normal)
|
||||
|
||||
|
||||
def resolve_attribute(term, attr):
|
||||
"""
|
||||
Resolve a terminal attribute name into a capability class.
|
||||
|
||||
:arg Terminal term: :class:`~.Terminal` instance.
|
||||
:arg str attr: Sugary, ordinary, or compound formatted terminal
|
||||
capability, such as "red_on_white", "normal", "red", or
|
||||
"bold_on_black".
|
||||
:returns: a string class instance which emits the terminal sequence
|
||||
for the given terminal capability, or may be used as a callable to
|
||||
wrap the given string with such sequence.
|
||||
:returns: :class:`NullCallableString` when
|
||||
:attr:`~.Terminal.number_of_colors` is 0,
|
||||
otherwise :class:`FormattingString`.
|
||||
:rtype: :class:`NullCallableString` or :class:`FormattingString`
|
||||
"""
|
||||
if attr in COLORS:
|
||||
return resolve_color(term, attr)
|
||||
|
||||
# A direct compoundable, such as `bold' or `on_red'.
|
||||
if attr in COMPOUNDABLES:
|
||||
sequence = resolve_capability(term, attr)
|
||||
return FormattingString(sequence, term.normal)
|
||||
|
||||
# Given `bold_on_red', resolve to ('bold', 'on_red'), RECURSIVE
|
||||
# call for each compounding section, joined and returned as
|
||||
# a completed completed FormattingString.
|
||||
formatters = split_compound(attr)
|
||||
if all((fmt in COLORS or fmt in COMPOUNDABLES) for fmt in formatters):
|
||||
resolution = (resolve_attribute(term, fmt) for fmt in formatters)
|
||||
return FormattingString(u''.join(resolution), term.normal)
|
||||
|
||||
# otherwise, this is our end-game: given a sequence such as 'csr'
|
||||
# (change scrolling region), return a ParameterizingString instance,
|
||||
# that when called, performs and returns the final string after curses
|
||||
# capability lookup is performed.
|
||||
tparm_capseq = resolve_capability(term, attr)
|
||||
if not tparm_capseq:
|
||||
# and, for special terminals, such as 'screen', provide a Proxy
|
||||
# ParameterizingString for attributes they do not claim to support,
|
||||
# but actually do! (such as 'hpa' and 'vpa').
|
||||
proxy = get_proxy_string(term,
|
||||
term._sugar.get(attr, attr)) # pylint: disable=protected-access
|
||||
if proxy is not None:
|
||||
return proxy
|
||||
|
||||
return ParameterizingString(tparm_capseq, term.normal, attr)
|
|
@ -0,0 +1,70 @@
|
|||
# std imports
|
||||
from typing import (Any,
|
||||
Set,
|
||||
List,
|
||||
Type,
|
||||
Tuple,
|
||||
Union,
|
||||
TypeVar,
|
||||
Callable,
|
||||
NoReturn,
|
||||
Optional,
|
||||
overload)
|
||||
|
||||
# local
|
||||
from .terminal import Terminal
|
||||
|
||||
COLORS: Set[str]
|
||||
COMPOUNDABLES: Set[str]
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
class ParameterizingString(str):
|
||||
def __new__(cls: Type[_T], cap: str, normal: str = ..., name: str = ...) -> _T: ...
|
||||
@overload
|
||||
def __call__(
|
||||
self, *args: int
|
||||
) -> Union["FormattingString", "NullCallableString"]: ...
|
||||
@overload
|
||||
def __call__(self, *args: str) -> NoReturn: ...
|
||||
|
||||
class ParameterizingProxyString(str):
|
||||
def __new__(
|
||||
cls: Type[_T],
|
||||
fmt_pair: Tuple[str, Callable[..., Tuple[object, ...]]],
|
||||
normal: str = ...,
|
||||
name: str = ...,
|
||||
) -> _T: ...
|
||||
def __call__(self, *args: Any) -> "FormattingString": ...
|
||||
|
||||
class FormattingString(str):
|
||||
def __new__(cls: Type[_T], sequence: str, normal: str = ...) -> _T: ...
|
||||
@overload
|
||||
def __call__(self, *args: int) -> NoReturn: ...
|
||||
@overload
|
||||
def __call__(self, *args: str) -> str: ...
|
||||
|
||||
class FormattingOtherString(str):
|
||||
def __new__(
|
||||
cls: Type[_T], direct: ParameterizingString, target: ParameterizingString = ...
|
||||
) -> _T: ...
|
||||
def __call__(self, *args: Union[int, str]) -> str: ...
|
||||
|
||||
class NullCallableString(str):
|
||||
def __new__(cls: Type[_T]) -> _T: ...
|
||||
@overload
|
||||
def __call__(self, *args: int) -> "NullCallableString": ...
|
||||
@overload
|
||||
def __call__(self, *args: str) -> str: ...
|
||||
|
||||
def get_proxy_string(
|
||||
term: Terminal, attr: str
|
||||
) -> Optional[ParameterizingProxyString]: ...
|
||||
def split_compound(compound: str) -> List[str]: ...
|
||||
def resolve_capability(term: Terminal, attr: str) -> str: ...
|
||||
def resolve_color(
|
||||
term: Terminal, color: str
|
||||
) -> Union[NullCallableString, FormattingString]: ...
|
||||
def resolve_attribute(
|
||||
term: Terminal, attr: str
|
||||
) -> Union[ParameterizingString, FormattingString]: ...
|
|
@ -0,0 +1,449 @@
|
|||
"""Sub-module providing 'keyboard awareness'."""
|
||||
|
||||
# std imports
|
||||
import re
|
||||
import time
|
||||
import platform
|
||||
from collections import OrderedDict
|
||||
|
||||
# 3rd party
|
||||
import six
|
||||
|
||||
# isort: off
|
||||
# curses
|
||||
if platform.system() == 'Windows':
|
||||
# pylint: disable=import-error
|
||||
import jinxed as curses
|
||||
from jinxed.has_key import _capability_names as capability_names
|
||||
else:
|
||||
import curses
|
||||
from curses.has_key import _capability_names as capability_names
|
||||
|
||||
|
||||
class Keystroke(six.text_type):
|
||||
"""
|
||||
A unicode-derived class for describing a single keystroke.
|
||||
|
||||
A class instance describes a single keystroke received on input,
|
||||
which may contain multiple characters as a multibyte sequence,
|
||||
which is indicated by properties :attr:`is_sequence` returning
|
||||
``True``.
|
||||
|
||||
When the string is a known sequence, :attr:`code` matches terminal
|
||||
class attributes for comparison, such as ``term.KEY_LEFT``.
|
||||
|
||||
The string-name of the sequence, such as ``u'KEY_LEFT'`` is accessed
|
||||
by property :attr:`name`, and is used by the :meth:`__repr__` method
|
||||
to display a human-readable form of the Keystroke this class
|
||||
instance represents. It may otherwise by joined, split, or evaluated
|
||||
just as as any other unicode string.
|
||||
"""
|
||||
|
||||
def __new__(cls, ucs='', code=None, name=None):
|
||||
"""Class constructor."""
|
||||
new = six.text_type.__new__(cls, ucs)
|
||||
new._name = name
|
||||
new._code = code
|
||||
return new
|
||||
|
||||
@property
|
||||
def is_sequence(self):
|
||||
"""Whether the value represents a multibyte sequence (bool)."""
|
||||
return self._code is not None
|
||||
|
||||
def __repr__(self):
|
||||
"""Docstring overwritten."""
|
||||
return (six.text_type.__repr__(self) if self._name is None else
|
||||
self._name)
|
||||
__repr__.__doc__ = six.text_type.__doc__
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""String-name of key sequence, such as ``u'KEY_LEFT'`` (str)."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
"""Integer keycode value of multibyte sequence (int)."""
|
||||
return self._code
|
||||
|
||||
|
||||
def get_curses_keycodes():
|
||||
"""
|
||||
Return mapping of curses key-names paired by their keycode integer value.
|
||||
|
||||
:rtype: dict
|
||||
:returns: Dictionary of (name, code) pairs for curses keyboard constant
|
||||
values and their mnemonic name. Such as code ``260``, with the value of
|
||||
its key-name identity, ``u'KEY_LEFT'``.
|
||||
"""
|
||||
_keynames = [attr for attr in dir(curses)
|
||||
if attr.startswith('KEY_')]
|
||||
return {keyname: getattr(curses, keyname) for keyname in _keynames}
|
||||
|
||||
|
||||
def get_keyboard_codes():
|
||||
"""
|
||||
Return mapping of keycode integer values paired by their curses key-name.
|
||||
|
||||
:rtype: dict
|
||||
:returns: Dictionary of (code, name) pairs for curses keyboard constant
|
||||
values and their mnemonic name. Such as key ``260``, with the value of
|
||||
its identity, ``u'KEY_LEFT'``.
|
||||
|
||||
These keys are derived from the attributes by the same of the curses module,
|
||||
with the following exceptions:
|
||||
|
||||
* ``KEY_DELETE`` in place of ``KEY_DC``
|
||||
* ``KEY_INSERT`` in place of ``KEY_IC``
|
||||
* ``KEY_PGUP`` in place of ``KEY_PPAGE``
|
||||
* ``KEY_PGDOWN`` in place of ``KEY_NPAGE``
|
||||
* ``KEY_ESCAPE`` in place of ``KEY_EXIT``
|
||||
* ``KEY_SUP`` in place of ``KEY_SR``
|
||||
* ``KEY_SDOWN`` in place of ``KEY_SF``
|
||||
|
||||
This function is the inverse of :func:`get_curses_keycodes`. With the
|
||||
given override "mixins" listed above, the keycode for the delete key will
|
||||
map to our imaginary ``KEY_DELETE`` mnemonic, effectively erasing the
|
||||
phrase ``KEY_DC`` from our code vocabulary for anyone that wishes to use
|
||||
the return value to determine the key-name by keycode.
|
||||
"""
|
||||
keycodes = OrderedDict(get_curses_keycodes())
|
||||
keycodes.update(CURSES_KEYCODE_OVERRIDE_MIXIN)
|
||||
# merge _CURSES_KEYCODE_ADDINS added to our module space
|
||||
keycodes.update((name, value) for name, value in globals().items() if name.startswith('KEY_'))
|
||||
|
||||
# invert dictionary (key, values) => (values, key), preferring the
|
||||
# last-most inserted value ('KEY_DELETE' over 'KEY_DC').
|
||||
return dict(zip(keycodes.values(), keycodes.keys()))
|
||||
|
||||
|
||||
def _alternative_left_right(term):
|
||||
r"""
|
||||
Determine and return mapping of left and right arrow keys sequences.
|
||||
|
||||
:arg blessed.Terminal term: :class:`~.Terminal` instance.
|
||||
:rtype: dict
|
||||
:returns: Dictionary of sequences ``term._cuf1``, and ``term._cub1``,
|
||||
valued as ``KEY_RIGHT``, ``KEY_LEFT`` (when appropriate).
|
||||
|
||||
This function supports :func:`get_terminal_sequences` to discover
|
||||
the preferred input sequence for the left and right application keys.
|
||||
|
||||
It is necessary to check the value of these sequences to ensure we do not
|
||||
use ``u' '`` and ``u'\b'`` for ``KEY_RIGHT`` and ``KEY_LEFT``,
|
||||
preferring their true application key sequence, instead.
|
||||
"""
|
||||
# pylint: disable=protected-access
|
||||
keymap = {}
|
||||
if term._cuf1 and term._cuf1 != u' ':
|
||||
keymap[term._cuf1] = curses.KEY_RIGHT
|
||||
if term._cub1 and term._cub1 != u'\b':
|
||||
keymap[term._cub1] = curses.KEY_LEFT
|
||||
return keymap
|
||||
|
||||
|
||||
def get_keyboard_sequences(term):
|
||||
r"""
|
||||
Return mapping of keyboard sequences paired by keycodes.
|
||||
|
||||
:arg blessed.Terminal term: :class:`~.Terminal` instance.
|
||||
:returns: mapping of keyboard unicode sequences paired by keycodes
|
||||
as integer. This is used as the argument ``mapper`` to
|
||||
the supporting function :func:`resolve_sequence`.
|
||||
:rtype: OrderedDict
|
||||
|
||||
Initialize and return a keyboard map and sequence lookup table,
|
||||
(sequence, keycode) from :class:`~.Terminal` instance ``term``,
|
||||
where ``sequence`` is a multibyte input sequence of unicode
|
||||
characters, such as ``u'\x1b[D'``, and ``keycode`` is an integer
|
||||
value, matching curses constant such as term.KEY_LEFT.
|
||||
|
||||
The return value is an OrderedDict instance, with their keys
|
||||
sorted longest-first.
|
||||
"""
|
||||
# A small gem from curses.has_key that makes this all possible,
|
||||
# _capability_names: a lookup table of terminal capability names for
|
||||
# keyboard sequences (fe. kcub1, key_left), keyed by the values of
|
||||
# constants found beginning with KEY_ in the main curses module
|
||||
# (such as KEY_LEFT).
|
||||
#
|
||||
# latin1 encoding is used so that bytes in 8-bit range of 127-255
|
||||
# have equivalent chr() and unichr() values, so that the sequence
|
||||
# of a kermit or avatar terminal, for example, remains unchanged
|
||||
# in its byte sequence values even when represented by unicode.
|
||||
#
|
||||
sequence_map = dict((
|
||||
(seq.decode('latin1'), val)
|
||||
for (seq, val) in (
|
||||
(curses.tigetstr(cap), val)
|
||||
for (val, cap) in capability_names.items()
|
||||
) if seq
|
||||
) if term.does_styling else ())
|
||||
|
||||
sequence_map.update(_alternative_left_right(term))
|
||||
sequence_map.update(DEFAULT_SEQUENCE_MIXIN)
|
||||
|
||||
# This is for fast lookup matching of sequences, preferring
|
||||
# full-length sequence such as ('\x1b[D', KEY_LEFT)
|
||||
# over simple sequences such as ('\x1b', KEY_EXIT).
|
||||
return OrderedDict((
|
||||
(seq, sequence_map[seq]) for seq in sorted(
|
||||
sequence_map.keys(), key=len, reverse=True)))
|
||||
|
||||
|
||||
def get_leading_prefixes(sequences):
|
||||
"""
|
||||
Return a set of proper prefixes for given sequence of strings.
|
||||
|
||||
:arg iterable sequences
|
||||
:rtype: set
|
||||
:return: Set of all string prefixes
|
||||
|
||||
Given an iterable of strings, all textparts leading up to the final
|
||||
string is returned as a unique set. This function supports the
|
||||
:meth:`~.Terminal.inkey` method by determining whether the given
|
||||
input is a sequence that **may** lead to a final matching pattern.
|
||||
|
||||
>>> prefixes(['abc', 'abdf', 'e', 'jkl'])
|
||||
set([u'a', u'ab', u'abd', u'j', u'jk'])
|
||||
"""
|
||||
return {seq[:i] for seq in sequences for i in range(1, len(seq))}
|
||||
|
||||
|
||||
def resolve_sequence(text, mapper, codes):
|
||||
r"""
|
||||
Return a single :class:`Keystroke` instance for given sequence ``text``.
|
||||
|
||||
:arg str text: string of characters received from terminal input stream.
|
||||
:arg OrderedDict mapper: unicode multibyte sequences, such as ``u'\x1b[D'``
|
||||
paired by their integer value (260)
|
||||
:arg dict codes: a :type:`dict` of integer values (such as 260) paired
|
||||
by their mnemonic name, such as ``'KEY_LEFT'``.
|
||||
:rtype: Keystroke
|
||||
:returns: Keystroke instance for the given sequence
|
||||
|
||||
The given ``text`` may extend beyond a matching sequence, such as
|
||||
``u\x1b[Dxxx`` returns a :class:`Keystroke` instance of attribute
|
||||
:attr:`Keystroke.sequence` valued only ``u\x1b[D``. It is up to
|
||||
calls to determine that ``xxx`` remains unresolved.
|
||||
"""
|
||||
for sequence, code in mapper.items():
|
||||
if text.startswith(sequence):
|
||||
return Keystroke(ucs=sequence, code=code, name=codes[code])
|
||||
return Keystroke(ucs=text and text[0] or u'')
|
||||
|
||||
|
||||
def _time_left(stime, timeout):
|
||||
"""
|
||||
Return time remaining since ``stime`` before given ``timeout``.
|
||||
|
||||
This function assists determining the value of ``timeout`` for
|
||||
class method :meth:`~.Terminal.kbhit` and similar functions.
|
||||
|
||||
:arg float stime: starting time for measurement
|
||||
:arg float timeout: timeout period, may be set to None to
|
||||
indicate no timeout (where None is always returned).
|
||||
:rtype: float or int
|
||||
:returns: time remaining as float. If no time is remaining,
|
||||
then the integer ``0`` is returned.
|
||||
"""
|
||||
return max(0, timeout - (time.time() - stime)) if timeout else timeout
|
||||
|
||||
|
||||
def _read_until(term, pattern, timeout):
|
||||
"""
|
||||
Convenience read-until-pattern function, supporting :meth:`~.get_location`.
|
||||
|
||||
:arg blessed.Terminal term: :class:`~.Terminal` instance.
|
||||
:arg float timeout: timeout period, may be set to None to indicate no
|
||||
timeout (where 0 is always returned).
|
||||
:arg str pattern: target regular expression pattern to seek.
|
||||
:rtype: tuple
|
||||
:returns: tuple in form of ``(match, str)``, *match*
|
||||
may be :class:`re.MatchObject` if pattern is discovered
|
||||
in input stream before timeout has elapsed, otherwise
|
||||
None. ``str`` is any remaining text received exclusive
|
||||
of the matching pattern).
|
||||
|
||||
The reason a tuple containing non-matching data is returned, is that the
|
||||
consumer should push such data back into the input buffer by
|
||||
:meth:`~.Terminal.ungetch` if any was received.
|
||||
|
||||
For example, when a user is performing rapid input keystrokes while its
|
||||
terminal emulator surreptitiously responds to this in-band sequence, we
|
||||
must ensure any such keyboard data is well-received by the next call to
|
||||
term.inkey() without delay.
|
||||
"""
|
||||
stime = time.time()
|
||||
match, buf = None, u''
|
||||
|
||||
# first, buffer all pending data. pexpect library provides a
|
||||
# 'searchwindowsize' attribute that limits this memory region. We're not
|
||||
# concerned about OOM conditions: only (human) keyboard input and terminal
|
||||
# response sequences are expected.
|
||||
|
||||
while True: # pragma: no branch
|
||||
# block as long as necessary to ensure at least one character is
|
||||
# received on input or remaining timeout has elapsed.
|
||||
ucs = term.inkey(timeout=_time_left(stime, timeout))
|
||||
# while the keyboard buffer is "hot" (has input), we continue to
|
||||
# aggregate all awaiting data. We do this to ensure slow I/O
|
||||
# calls do not unnecessarily give up within the first 'while' loop
|
||||
# for short timeout periods.
|
||||
while ucs:
|
||||
buf += ucs
|
||||
ucs = term.inkey(timeout=0)
|
||||
|
||||
match = re.search(pattern=pattern, string=buf)
|
||||
if match is not None:
|
||||
# match
|
||||
break
|
||||
|
||||
if timeout is not None and not _time_left(stime, timeout):
|
||||
# timeout
|
||||
break
|
||||
|
||||
return match, buf
|
||||
|
||||
|
||||
#: Though we may determine *keynames* and codes for keyboard input that
|
||||
#: generate multibyte sequences, it is also especially useful to aliases
|
||||
#: a few basic ASCII characters such as ``KEY_TAB`` instead of ``u'\t'`` for
|
||||
#: uniformity.
|
||||
#:
|
||||
#: Furthermore, many key-names for application keys enabled only by context
|
||||
#: manager :meth:`~.Terminal.keypad` are surprisingly absent. We inject them
|
||||
#: here directly into the curses module.
|
||||
_CURSES_KEYCODE_ADDINS = (
|
||||
'TAB',
|
||||
'KP_MULTIPLY',
|
||||
'KP_ADD',
|
||||
'KP_SEPARATOR',
|
||||
'KP_SUBTRACT',
|
||||
'KP_DECIMAL',
|
||||
'KP_DIVIDE',
|
||||
'KP_EQUAL',
|
||||
'KP_0',
|
||||
'KP_1',
|
||||
'KP_2',
|
||||
'KP_3',
|
||||
'KP_4',
|
||||
'KP_5',
|
||||
'KP_6',
|
||||
'KP_7',
|
||||
'KP_8',
|
||||
'KP_9')
|
||||
|
||||
_LASTVAL = max(get_curses_keycodes().values())
|
||||
for keycode_name in _CURSES_KEYCODE_ADDINS:
|
||||
_LASTVAL += 1
|
||||
globals()['KEY_' + keycode_name] = _LASTVAL
|
||||
|
||||
#: In a perfect world, terminal emulators would always send exactly what
|
||||
#: the terminfo(5) capability database plans for them, accordingly by the
|
||||
#: value of the ``TERM`` name they declare.
|
||||
#:
|
||||
#: But this isn't a perfect world. Many vt220-derived terminals, such as
|
||||
#: those declaring 'xterm', will continue to send vt220 codes instead of
|
||||
#: their native-declared codes, for backwards-compatibility.
|
||||
#:
|
||||
#: This goes for many: rxvt, putty, iTerm.
|
||||
#:
|
||||
#: These "mixins" are used for *all* terminals, regardless of their type.
|
||||
#:
|
||||
#: Furthermore, curses does not provide sequences sent by the keypad,
|
||||
#: at least, it does not provide a way to distinguish between keypad 0
|
||||
#: and numeric 0.
|
||||
DEFAULT_SEQUENCE_MIXIN = (
|
||||
# these common control characters (and 127, ctrl+'?') mapped to
|
||||
# an application key definition.
|
||||
(six.unichr(10), curses.KEY_ENTER),
|
||||
(six.unichr(13), curses.KEY_ENTER),
|
||||
(six.unichr(8), curses.KEY_BACKSPACE),
|
||||
(six.unichr(9), KEY_TAB), # noqa # pylint: disable=undefined-variable
|
||||
(six.unichr(27), curses.KEY_EXIT),
|
||||
(six.unichr(127), curses.KEY_BACKSPACE),
|
||||
|
||||
(u"\x1b[A", curses.KEY_UP),
|
||||
(u"\x1b[B", curses.KEY_DOWN),
|
||||
(u"\x1b[C", curses.KEY_RIGHT),
|
||||
(u"\x1b[D", curses.KEY_LEFT),
|
||||
(u"\x1b[1;2A", curses.KEY_SR),
|
||||
(u"\x1b[1;2B", curses.KEY_SF),
|
||||
(u"\x1b[1;2C", curses.KEY_SRIGHT),
|
||||
(u"\x1b[1;2D", curses.KEY_SLEFT),
|
||||
(u"\x1b[F", curses.KEY_END),
|
||||
(u"\x1b[H", curses.KEY_HOME),
|
||||
# not sure where these are from .. please report
|
||||
(u"\x1b[K", curses.KEY_END),
|
||||
(u"\x1b[U", curses.KEY_NPAGE),
|
||||
(u"\x1b[V", curses.KEY_PPAGE),
|
||||
|
||||
# keys sent after term.smkx (keypad_xmit) is emitted, source:
|
||||
# http://www.xfree86.org/current/ctlseqs.html#PC-Style%20Function%20Keys
|
||||
# http://fossies.org/linux/rxvt/doc/rxvtRef.html#KeyCodes
|
||||
#
|
||||
# keypad, numlock on
|
||||
(u"\x1bOM", curses.KEY_ENTER), # noqa return
|
||||
(u"\x1bOj", KEY_KP_MULTIPLY), # noqa * # pylint: disable=undefined-variable
|
||||
(u"\x1bOk", KEY_KP_ADD), # noqa + # pylint: disable=undefined-variable
|
||||
(u"\x1bOl", KEY_KP_SEPARATOR), # noqa , # pylint: disable=undefined-variable
|
||||
(u"\x1bOm", KEY_KP_SUBTRACT), # noqa - # pylint: disable=undefined-variable
|
||||
(u"\x1bOn", KEY_KP_DECIMAL), # noqa . # pylint: disable=undefined-variable
|
||||
(u"\x1bOo", KEY_KP_DIVIDE), # noqa / # pylint: disable=undefined-variable
|
||||
(u"\x1bOX", KEY_KP_EQUAL), # noqa = # pylint: disable=undefined-variable
|
||||
(u"\x1bOp", KEY_KP_0), # noqa 0 # pylint: disable=undefined-variable
|
||||
(u"\x1bOq", KEY_KP_1), # noqa 1 # pylint: disable=undefined-variable
|
||||
(u"\x1bOr", KEY_KP_2), # noqa 2 # pylint: disable=undefined-variable
|
||||
(u"\x1bOs", KEY_KP_3), # noqa 3 # pylint: disable=undefined-variable
|
||||
(u"\x1bOt", KEY_KP_4), # noqa 4 # pylint: disable=undefined-variable
|
||||
(u"\x1bOu", KEY_KP_5), # noqa 5 # pylint: disable=undefined-variable
|
||||
(u"\x1bOv", KEY_KP_6), # noqa 6 # pylint: disable=undefined-variable
|
||||
(u"\x1bOw", KEY_KP_7), # noqa 7 # pylint: disable=undefined-variable
|
||||
(u"\x1bOx", KEY_KP_8), # noqa 8 # pylint: disable=undefined-variable
|
||||
(u"\x1bOy", KEY_KP_9), # noqa 9 # pylint: disable=undefined-variable
|
||||
|
||||
# keypad, numlock off
|
||||
(u"\x1b[1~", curses.KEY_FIND), # find
|
||||
(u"\x1b[2~", curses.KEY_IC), # insert (0)
|
||||
(u"\x1b[3~", curses.KEY_DC), # delete (.), "Execute"
|
||||
(u"\x1b[4~", curses.KEY_SELECT), # select
|
||||
(u"\x1b[5~", curses.KEY_PPAGE), # pgup (9)
|
||||
(u"\x1b[6~", curses.KEY_NPAGE), # pgdown (3)
|
||||
(u"\x1b[7~", curses.KEY_HOME), # home
|
||||
(u"\x1b[8~", curses.KEY_END), # end
|
||||
(u"\x1b[OA", curses.KEY_UP), # up (8)
|
||||
(u"\x1b[OB", curses.KEY_DOWN), # down (2)
|
||||
(u"\x1b[OC", curses.KEY_RIGHT), # right (6)
|
||||
(u"\x1b[OD", curses.KEY_LEFT), # left (4)
|
||||
(u"\x1b[OF", curses.KEY_END), # end (1)
|
||||
(u"\x1b[OH", curses.KEY_HOME), # home (7)
|
||||
|
||||
# The vt220 placed F1-F4 above the keypad, in place of actual
|
||||
# F1-F4 were local functions (hold screen, print screen,
|
||||
# set up, data/talk, break).
|
||||
(u"\x1bOP", curses.KEY_F1),
|
||||
(u"\x1bOQ", curses.KEY_F2),
|
||||
(u"\x1bOR", curses.KEY_F3),
|
||||
(u"\x1bOS", curses.KEY_F4),
|
||||
)
|
||||
|
||||
#: Override mixins for a few curses constants with easier
|
||||
#: mnemonics: there may only be a 1:1 mapping when only a
|
||||
#: keycode (int) is given, where these phrases are preferred.
|
||||
CURSES_KEYCODE_OVERRIDE_MIXIN = (
|
||||
('KEY_DELETE', curses.KEY_DC),
|
||||
('KEY_INSERT', curses.KEY_IC),
|
||||
('KEY_PGUP', curses.KEY_PPAGE),
|
||||
('KEY_PGDOWN', curses.KEY_NPAGE),
|
||||
('KEY_ESCAPE', curses.KEY_EXIT),
|
||||
('KEY_SUP', curses.KEY_SR),
|
||||
('KEY_SDOWN', curses.KEY_SF),
|
||||
('KEY_UP_LEFT', curses.KEY_A1),
|
||||
('KEY_UP_RIGHT', curses.KEY_A3),
|
||||
('KEY_CENTER', curses.KEY_B2),
|
||||
('KEY_BEGIN', curses.KEY_BEG),
|
||||
)
|
||||
|
||||
__all__ = ('Keystroke', 'get_keyboard_codes', 'get_keyboard_sequences',)
|
|
@ -0,0 +1,28 @@
|
|||
# std imports
|
||||
from typing import Set, Dict, Type, Mapping, TypeVar, Iterable, Optional, OrderedDict
|
||||
|
||||
# local
|
||||
from .terminal import Terminal
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
class Keystroke(str):
|
||||
def __new__(
|
||||
cls: Type[_T],
|
||||
ucs: str = ...,
|
||||
code: Optional[int] = ...,
|
||||
name: Optional[str] = ...,
|
||||
) -> _T: ...
|
||||
@property
|
||||
def is_sequence(self) -> bool: ...
|
||||
@property
|
||||
def name(self) -> Optional[str]: ...
|
||||
@property
|
||||
def code(self) -> Optional[int]: ...
|
||||
|
||||
def get_keyboard_codes() -> Dict[int, str]: ...
|
||||
def get_keyboard_sequences(term: Terminal) -> OrderedDict[str, int]: ...
|
||||
def get_leading_prefixes(sequences: Iterable[str]) -> Set[str]: ...
|
||||
def resolve_sequence(
|
||||
text: str, mapper: Mapping[str, int], codes: Mapping[int, str]
|
||||
) -> Keystroke: ...
|
|
@ -0,0 +1,461 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Module providing 'sequence awareness'."""
|
||||
# std imports
|
||||
import re
|
||||
import math
|
||||
import textwrap
|
||||
|
||||
# 3rd party
|
||||
import six
|
||||
from wcwidth import wcwidth
|
||||
|
||||
# local
|
||||
from blessed._capabilities import CAPABILITIES_CAUSE_MOVEMENT
|
||||
|
||||
__all__ = ('Sequence', 'SequenceTextWrapper', 'iter_parse', 'measure_length')
|
||||
|
||||
|
||||
class Termcap(object):
|
||||
"""Terminal capability of given variable name and pattern."""
|
||||
|
||||
def __init__(self, name, pattern, attribute):
|
||||
"""
|
||||
Class initializer.
|
||||
|
||||
:arg str name: name describing capability.
|
||||
:arg str pattern: regular expression string.
|
||||
:arg str attribute: :class:`~.Terminal` attribute used to build
|
||||
this terminal capability.
|
||||
"""
|
||||
self.name = name
|
||||
self.pattern = pattern
|
||||
self.attribute = attribute
|
||||
self._re_compiled = None
|
||||
|
||||
def __repr__(self):
|
||||
# pylint: disable=redundant-keyword-arg
|
||||
return '<Termcap {self.name}:{self.pattern!r}>'.format(self=self)
|
||||
|
||||
@property
|
||||
def named_pattern(self):
|
||||
"""Regular expression pattern for capability with named group."""
|
||||
# pylint: disable=redundant-keyword-arg
|
||||
return '(?P<{self.name}>{self.pattern})'.format(self=self)
|
||||
|
||||
@property
|
||||
def re_compiled(self):
|
||||
"""Compiled regular expression pattern for capability."""
|
||||
if self._re_compiled is None:
|
||||
self._re_compiled = re.compile(self.pattern)
|
||||
return self._re_compiled
|
||||
|
||||
@property
|
||||
def will_move(self):
|
||||
"""Whether capability causes cursor movement."""
|
||||
return self.name in CAPABILITIES_CAUSE_MOVEMENT
|
||||
|
||||
def horizontal_distance(self, text):
|
||||
"""
|
||||
Horizontal carriage adjusted by capability, may be negative.
|
||||
|
||||
:rtype: int
|
||||
:arg str text: for capabilities *parm_left_cursor*,
|
||||
*parm_right_cursor*, provide the matching sequence
|
||||
text, its interpreted distance is returned.
|
||||
|
||||
:returns: 0 except for matching '
|
||||
"""
|
||||
value = {
|
||||
'cursor_left': -1,
|
||||
'backspace': -1,
|
||||
'cursor_right': 1,
|
||||
'tab': 8,
|
||||
'ascii_tab': 8,
|
||||
}.get(self.name, None)
|
||||
if value is not None:
|
||||
return value
|
||||
|
||||
unit = {
|
||||
'parm_left_cursor': -1,
|
||||
'parm_right_cursor': 1
|
||||
}.get(self.name, None)
|
||||
if unit is not None:
|
||||
value = int(self.re_compiled.match(text).group(1))
|
||||
return unit * value
|
||||
|
||||
return 0
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
@classmethod
|
||||
def build(cls, name, capability, attribute, nparams=0,
|
||||
numeric=99, match_grouped=False, match_any=False,
|
||||
match_optional=False):
|
||||
r"""
|
||||
Class factory builder for given capability definition.
|
||||
|
||||
:arg str name: Variable name given for this pattern.
|
||||
:arg str capability: A unicode string representing a terminal
|
||||
capability to build for. When ``nparams`` is non-zero, it
|
||||
must be a callable unicode string (such as the result from
|
||||
``getattr(term, 'bold')``.
|
||||
:arg str attribute: The terminfo(5) capability name by which this
|
||||
pattern is known.
|
||||
:arg int nparams: number of positional arguments for callable.
|
||||
:arg int numeric: Value to substitute into capability to when generating pattern
|
||||
:arg bool match_grouped: If the numeric pattern should be
|
||||
grouped, ``(\d+)`` when ``True``, ``\d+`` default.
|
||||
:arg bool match_any: When keyword argument ``nparams`` is given,
|
||||
*any* numeric found in output is suitable for building as
|
||||
pattern ``(\d+)``. Otherwise, only the first matching value of
|
||||
range *(numeric - 1)* through *(numeric + 1)* will be replaced by
|
||||
pattern ``(\d+)`` in builder.
|
||||
:arg bool match_optional: When ``True``, building of numeric patterns
|
||||
containing ``(\d+)`` will be built as optional, ``(\d+)?``.
|
||||
:rtype: blessed.sequences.Termcap
|
||||
:returns: Terminal capability instance for given capability definition
|
||||
"""
|
||||
_numeric_regex = r'\d+'
|
||||
if match_grouped:
|
||||
_numeric_regex = r'(\d+)'
|
||||
if match_optional:
|
||||
_numeric_regex = r'(\d+)?'
|
||||
numeric = 99 if numeric is None else numeric
|
||||
|
||||
# basic capability attribute, not used as a callable
|
||||
if nparams == 0:
|
||||
return cls(name, re.escape(capability), attribute)
|
||||
|
||||
# a callable capability accepting numeric argument
|
||||
_outp = re.escape(capability(*(numeric,) * nparams))
|
||||
if not match_any:
|
||||
for num in range(numeric - 1, numeric + 2):
|
||||
if str(num) in _outp:
|
||||
pattern = _outp.replace(str(num), _numeric_regex)
|
||||
return cls(name, pattern, attribute)
|
||||
|
||||
if match_grouped:
|
||||
pattern = re.sub(r'(\d+)', lambda x: _numeric_regex, _outp)
|
||||
else:
|
||||
pattern = re.sub(r'\d+', lambda x: _numeric_regex, _outp)
|
||||
return cls(name, pattern, attribute)
|
||||
|
||||
|
||||
class SequenceTextWrapper(textwrap.TextWrapper):
|
||||
"""Docstring overridden."""
|
||||
|
||||
def __init__(self, width, term, **kwargs):
|
||||
"""
|
||||
Class initializer.
|
||||
|
||||
This class supports the :meth:`~.Terminal.wrap` method.
|
||||
"""
|
||||
self.term = term
|
||||
textwrap.TextWrapper.__init__(self, width, **kwargs)
|
||||
|
||||
def _wrap_chunks(self, chunks):
|
||||
"""
|
||||
Sequence-aware variant of :meth:`textwrap.TextWrapper._wrap_chunks`.
|
||||
|
||||
:raises ValueError: ``self.width`` is not a positive integer
|
||||
:rtype: list
|
||||
:returns: text chunks adjusted for width
|
||||
|
||||
This simply ensures that word boundaries are not broken mid-sequence, as standard python
|
||||
textwrap would incorrectly determine the length of a string containing sequences, and may
|
||||
also break consider sequences part of a "word" that may be broken by hyphen (``-``), where
|
||||
this implementation corrects both.
|
||||
"""
|
||||
lines = []
|
||||
if self.width <= 0 or not isinstance(self.width, int):
|
||||
raise ValueError(
|
||||
"invalid width {0!r}({1!r}) (must be integer > 0)"
|
||||
.format(self.width, type(self.width)))
|
||||
|
||||
term = self.term
|
||||
drop_whitespace = not hasattr(self, 'drop_whitespace'
|
||||
) or self.drop_whitespace
|
||||
chunks.reverse()
|
||||
while chunks:
|
||||
cur_line = []
|
||||
cur_len = 0
|
||||
indent = self.subsequent_indent if lines else self.initial_indent
|
||||
width = self.width - len(indent)
|
||||
if drop_whitespace and (
|
||||
Sequence(chunks[-1], term).strip() == '' and lines):
|
||||
del chunks[-1]
|
||||
while chunks:
|
||||
chunk_len = Sequence(chunks[-1], term).length()
|
||||
if cur_len + chunk_len > width:
|
||||
break
|
||||
cur_line.append(chunks.pop())
|
||||
cur_len += chunk_len
|
||||
if chunks and Sequence(chunks[-1], term).length() > width:
|
||||
self._handle_long_word(chunks, cur_line, cur_len, width)
|
||||
if drop_whitespace and (
|
||||
cur_line and Sequence(cur_line[-1], term).strip() == ''):
|
||||
del cur_line[-1]
|
||||
if cur_line:
|
||||
lines.append(indent + u''.join(cur_line))
|
||||
return lines
|
||||
|
||||
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
|
||||
"""
|
||||
Sequence-aware :meth:`textwrap.TextWrapper._handle_long_word`.
|
||||
|
||||
This simply ensures that word boundaries are not broken mid-sequence, as standard python
|
||||
textwrap would incorrectly determine the length of a string containing sequences, and may
|
||||
also break consider sequences part of a "word" that may be broken by hyphen (``-``), where
|
||||
this implementation corrects both.
|
||||
"""
|
||||
# Figure out when indent is larger than the specified width, and make
|
||||
# sure at least one character is stripped off on every pass
|
||||
space_left = 1 if width < 1 else width - cur_len
|
||||
# If we're allowed to break long words, then do so: put as much
|
||||
# of the next chunk onto the current line as will fit.
|
||||
|
||||
if self.break_long_words:
|
||||
term = self.term
|
||||
chunk = reversed_chunks[-1]
|
||||
idx = nxt = 0
|
||||
for text, _ in iter_parse(term, chunk):
|
||||
nxt += len(text)
|
||||
if Sequence(chunk[:nxt], term).length() > space_left:
|
||||
break
|
||||
idx = nxt
|
||||
cur_line.append(chunk[:idx])
|
||||
reversed_chunks[-1] = chunk[idx:]
|
||||
|
||||
# Otherwise, we have to preserve the long word intact. Only add
|
||||
# it to the current line if there's nothing already there --
|
||||
# that minimizes how much we violate the width constraint.
|
||||
elif not cur_line:
|
||||
cur_line.append(reversed_chunks.pop())
|
||||
|
||||
# If we're not allowed to break long words, and there's already
|
||||
# text on the current line, do nothing. Next time through the
|
||||
# main loop of _wrap_chunks(), we'll wind up here again, but
|
||||
# cur_len will be zero, so the next line will be entirely
|
||||
# devoted to the long word that we can't handle right now.
|
||||
|
||||
|
||||
SequenceTextWrapper.__doc__ = textwrap.TextWrapper.__doc__
|
||||
|
||||
|
||||
class Sequence(six.text_type):
|
||||
"""
|
||||
A "sequence-aware" version of the base :class:`str` class.
|
||||
|
||||
This unicode-derived class understands the effect of escape sequences
|
||||
of printable length, allowing a properly implemented :meth:`rjust`,
|
||||
:meth:`ljust`, :meth:`center`, and :meth:`length`.
|
||||
"""
|
||||
|
||||
def __new__(cls, sequence_text, term):
|
||||
# pylint: disable = missing-return-doc, missing-return-type-doc
|
||||
"""
|
||||
Class constructor.
|
||||
|
||||
:arg str sequence_text: A string that may contain sequences.
|
||||
:arg blessed.Terminal term: :class:`~.Terminal` instance.
|
||||
"""
|
||||
new = six.text_type.__new__(cls, sequence_text)
|
||||
new._term = term
|
||||
return new
|
||||
|
||||
def ljust(self, width, fillchar=u' '):
|
||||
"""
|
||||
Return string containing sequences, left-adjusted.
|
||||
|
||||
:arg int width: Total width given to left-adjust ``text``. If
|
||||
unspecified, the width of the attached terminal is used (default).
|
||||
:arg str fillchar: String for padding right-of ``text``.
|
||||
:returns: String of ``text``, left-aligned by ``width``.
|
||||
:rtype: str
|
||||
"""
|
||||
rightside = fillchar * int(
|
||||
(max(0.0, float(width.__index__() - self.length()))) / float(len(fillchar)))
|
||||
return u''.join((self, rightside))
|
||||
|
||||
def rjust(self, width, fillchar=u' '):
|
||||
"""
|
||||
Return string containing sequences, right-adjusted.
|
||||
|
||||
:arg int width: Total width given to right-adjust ``text``. If
|
||||
unspecified, the width of the attached terminal is used (default).
|
||||
:arg str fillchar: String for padding left-of ``text``.
|
||||
:returns: String of ``text``, right-aligned by ``width``.
|
||||
:rtype: str
|
||||
"""
|
||||
leftside = fillchar * int(
|
||||
(max(0.0, float(width.__index__() - self.length()))) / float(len(fillchar)))
|
||||
return u''.join((leftside, self))
|
||||
|
||||
def center(self, width, fillchar=u' '):
|
||||
"""
|
||||
Return string containing sequences, centered.
|
||||
|
||||
:arg int width: Total width given to center ``text``. If
|
||||
unspecified, the width of the attached terminal is used (default).
|
||||
:arg str fillchar: String for padding left and right-of ``text``.
|
||||
:returns: String of ``text``, centered by ``width``.
|
||||
:rtype: str
|
||||
"""
|
||||
split = max(0.0, float(width.__index__()) - self.length()) / 2
|
||||
leftside = fillchar * int(
|
||||
(max(0.0, math.floor(split))) / float(len(fillchar)))
|
||||
rightside = fillchar * int(
|
||||
(max(0.0, math.ceil(split))) / float(len(fillchar)))
|
||||
return u''.join((leftside, self, rightside))
|
||||
|
||||
def truncate(self, width):
|
||||
"""
|
||||
Truncate a string in a sequence-aware manner.
|
||||
|
||||
Any printable characters beyond ``width`` are removed, while all
|
||||
sequences remain in place. Horizontal Sequences are first expanded
|
||||
by :meth:`padd`.
|
||||
|
||||
:arg int width: The printable width to truncate the string to.
|
||||
:rtype: str
|
||||
:returns: String truncated to at most ``width`` printable characters.
|
||||
"""
|
||||
output = ""
|
||||
current_width = 0
|
||||
target_width = width.__index__()
|
||||
parsed_seq = iter_parse(self._term, self.padd())
|
||||
|
||||
# Retain all text until non-cap width reaches desired width
|
||||
for text, cap in parsed_seq:
|
||||
if not cap:
|
||||
# use wcwidth clipped to 0 because it can sometimes return -1
|
||||
current_width += max(wcwidth(text), 0)
|
||||
if current_width > target_width:
|
||||
break
|
||||
output += text
|
||||
|
||||
# Return with remaining caps appended
|
||||
return output + ''.join(text for text, cap in parsed_seq if cap)
|
||||
|
||||
def length(self):
|
||||
r"""
|
||||
Return the printable length of string containing sequences.
|
||||
|
||||
Strings containing ``term.left`` or ``\b`` will cause "overstrike",
|
||||
but a length less than 0 is not ever returned. So ``_\b+`` is a
|
||||
length of 1 (displays as ``+``), but ``\b`` alone is simply a
|
||||
length of 0.
|
||||
|
||||
Some characters may consume more than one cell, mainly those CJK
|
||||
Unified Ideographs (Chinese, Japanese, Korean) defined by Unicode
|
||||
as half or full-width characters.
|
||||
|
||||
For example:
|
||||
|
||||
>>> from blessed import Terminal
|
||||
>>> from blessed.sequences import Sequence
|
||||
>>> term = Terminal()
|
||||
>>> msg = term.clear + term.red(u'コンニチハ')
|
||||
>>> Sequence(msg, term).length()
|
||||
10
|
||||
|
||||
.. note:: Although accounted for, strings containing sequences such
|
||||
as ``term.clear`` will not give accurate returns, it is not
|
||||
considered lengthy (a length of 0).
|
||||
"""
|
||||
# because control characters may return -1, "clip" their length to 0.
|
||||
return sum(max(wcwidth(w_char), 0) for w_char in self.padd(strip=True))
|
||||
|
||||
def strip(self, chars=None):
|
||||
"""
|
||||
Return string of sequences, leading and trailing whitespace removed.
|
||||
|
||||
:arg str chars: Remove characters in chars instead of whitespace.
|
||||
:rtype: str
|
||||
:returns: string of sequences with leading and trailing whitespace removed.
|
||||
"""
|
||||
return self.strip_seqs().strip(chars)
|
||||
|
||||
def lstrip(self, chars=None):
|
||||
"""
|
||||
Return string of all sequences and leading whitespace removed.
|
||||
|
||||
:arg str chars: Remove characters in chars instead of whitespace.
|
||||
:rtype: str
|
||||
:returns: string of sequences with leading removed.
|
||||
"""
|
||||
return self.strip_seqs().lstrip(chars)
|
||||
|
||||
def rstrip(self, chars=None):
|
||||
"""
|
||||
Return string of all sequences and trailing whitespace removed.
|
||||
|
||||
:arg str chars: Remove characters in chars instead of whitespace.
|
||||
:rtype: str
|
||||
:returns: string of sequences with trailing removed.
|
||||
"""
|
||||
return self.strip_seqs().rstrip(chars)
|
||||
|
||||
def strip_seqs(self):
|
||||
"""
|
||||
Return ``text`` stripped of only its terminal sequences.
|
||||
|
||||
:rtype: str
|
||||
:returns: Text with terminal sequences removed
|
||||
"""
|
||||
return self.padd(strip=True)
|
||||
|
||||
def padd(self, strip=False):
|
||||
"""
|
||||
Return non-destructive horizontal movement as destructive spacing.
|
||||
|
||||
:arg bool strip: Strip terminal sequences
|
||||
:rtype: str
|
||||
:returns: Text adjusted for horizontal movement
|
||||
"""
|
||||
outp = ''
|
||||
for text, cap in iter_parse(self._term, self):
|
||||
if not cap:
|
||||
outp += text
|
||||
continue
|
||||
|
||||
value = cap.horizontal_distance(text)
|
||||
if value > 0:
|
||||
outp += ' ' * value
|
||||
elif value < 0:
|
||||
outp = outp[:value]
|
||||
elif not strip:
|
||||
outp += text
|
||||
return outp
|
||||
|
||||
|
||||
def iter_parse(term, text):
|
||||
"""
|
||||
Generator yields (text, capability) for characters of ``text``.
|
||||
|
||||
value for ``capability`` may be ``None``, where ``text`` is
|
||||
:class:`str` of length 1. Otherwise, ``text`` is a full
|
||||
matching sequence of given capability.
|
||||
"""
|
||||
for match in term._caps_compiled_any.finditer(text): # pylint: disable=protected-access
|
||||
name = match.lastgroup
|
||||
value = match.group(name)
|
||||
if name == 'MISMATCH':
|
||||
yield (value, None)
|
||||
else:
|
||||
yield value, term.caps[name]
|
||||
|
||||
|
||||
def measure_length(text, term):
|
||||
"""
|
||||
.. deprecated:: 1.12.0.
|
||||
|
||||
:rtype: int
|
||||
:returns: Length of the first sequence in the string
|
||||
"""
|
||||
try:
|
||||
text, capability = next(iter_parse(term, text))
|
||||
if capability:
|
||||
return len(text)
|
||||
except StopIteration:
|
||||
return 0
|
||||
return 0
|
|
@ -0,0 +1,55 @@
|
|||
# std imports
|
||||
import textwrap
|
||||
from typing import Any, Type, Tuple, Pattern, TypeVar, Iterator, Optional, SupportsIndex
|
||||
|
||||
# local
|
||||
from .terminal import Terminal
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
class Termcap:
|
||||
name: str = ...
|
||||
pattern: str = ...
|
||||
attribute: str = ...
|
||||
def __init__(self, name: str, pattern: str, attribute: str) -> None: ...
|
||||
@property
|
||||
def named_pattern(self) -> str: ...
|
||||
@property
|
||||
def re_compiled(self) -> Pattern[str]: ...
|
||||
@property
|
||||
def will_move(self) -> bool: ...
|
||||
def horizontal_distance(self, text: str) -> int: ...
|
||||
@classmethod
|
||||
def build(
|
||||
cls,
|
||||
name: str,
|
||||
capability: str,
|
||||
attribute: str,
|
||||
nparams: int = ...,
|
||||
numeric: int = ...,
|
||||
match_grouped: bool = ...,
|
||||
match_any: bool = ...,
|
||||
match_optional: bool = ...,
|
||||
) -> "Termcap": ...
|
||||
|
||||
class SequenceTextWrapper(textwrap.TextWrapper):
|
||||
term: Terminal = ...
|
||||
def __init__(self, width: int, term: Terminal, **kwargs: Any) -> None: ...
|
||||
|
||||
class Sequence(str):
|
||||
def __new__(cls: Type[_T], sequence_text: str, term: Terminal) -> _T: ...
|
||||
def ljust(self, width: SupportsIndex, fillchar: str = ...) -> str: ...
|
||||
def rjust(self, width: SupportsIndex, fillchar: str = ...) -> str: ...
|
||||
def center(self, width: SupportsIndex, fillchar: str = ...) -> str: ...
|
||||
def truncate(self, width: SupportsIndex) -> str: ...
|
||||
def length(self) -> int: ...
|
||||
def strip(self, chars: Optional[str] = ...) -> str: ...
|
||||
def lstrip(self, chars: Optional[str] = ...) -> str: ...
|
||||
def rstrip(self, chars: Optional[str] = ...) -> str: ...
|
||||
def strip_seqs(self) -> str: ...
|
||||
def padd(self, strip: bool = ...) -> str: ...
|
||||
|
||||
def iter_parse(
|
||||
term: Terminal, text: str
|
||||
) -> Iterator[Tuple[str, Optional[Termcap]]]: ...
|
||||
def measure_length(text: str, term: Terminal) -> int: ...
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,106 @@
|
|||
# std imports
|
||||
from typing import IO, Any, List, Tuple, Union, Optional, OrderedDict, ContextManager
|
||||
|
||||
# local
|
||||
from .keyboard import Keystroke
|
||||
from .sequences import Termcap
|
||||
from .formatters import (FormattingString,
|
||||
NullCallableString,
|
||||
ParameterizingString,
|
||||
FormattingOtherString)
|
||||
|
||||
HAS_TTY: bool
|
||||
|
||||
class Terminal:
|
||||
caps: OrderedDict[str, Termcap]
|
||||
errors: List[str] = ...
|
||||
def __init__(
|
||||
self,
|
||||
kind: Optional[str] = ...,
|
||||
stream: Optional[IO[str]] = ...,
|
||||
force_styling: bool = ...,
|
||||
) -> None: ...
|
||||
def __getattr__(
|
||||
self, attr: str
|
||||
) -> Union[NullCallableString, ParameterizingString, FormattingString]: ...
|
||||
@property
|
||||
def kind(self) -> str: ...
|
||||
@property
|
||||
def does_styling(self) -> bool: ...
|
||||
@property
|
||||
def is_a_tty(self) -> bool: ...
|
||||
@property
|
||||
def height(self) -> int: ...
|
||||
@property
|
||||
def width(self) -> int: ...
|
||||
@property
|
||||
def pixel_height(self) -> int: ...
|
||||
@property
|
||||
def pixel_width(self) -> int: ...
|
||||
def location(
|
||||
self, x: Optional[int] = ..., y: Optional[int] = ...
|
||||
) -> ContextManager[None]: ...
|
||||
def get_location(self, timeout: Optional[float] = ...) -> Tuple[int, int]: ...
|
||||
def fullscreen(self) -> ContextManager[None]: ...
|
||||
def hidden_cursor(self) -> ContextManager[None]: ...
|
||||
def move_xy(self, x: int, y: int) -> ParameterizingString: ...
|
||||
def move_yx(self, y: int, x: int) -> ParameterizingString: ...
|
||||
@property
|
||||
def move_left(self) -> FormattingOtherString: ...
|
||||
@property
|
||||
def move_right(self) -> FormattingOtherString: ...
|
||||
@property
|
||||
def move_up(self) -> FormattingOtherString: ...
|
||||
@property
|
||||
def move_down(self) -> FormattingOtherString: ...
|
||||
@property
|
||||
def color(self) -> Union[NullCallableString, ParameterizingString]: ...
|
||||
def color_rgb(self, red: int, green: int, blue: int) -> FormattingString: ...
|
||||
@property
|
||||
def on_color(self) -> Union[NullCallableString, ParameterizingString]: ...
|
||||
def on_color_rgb(self, red: int, green: int, blue: int) -> FormattingString: ...
|
||||
def formatter(self, value: str) -> Union[NullCallableString, FormattingString]: ...
|
||||
def rgb_downconvert(self, red: int, green: int, blue: int) -> int: ...
|
||||
@property
|
||||
def normal(self) -> str: ...
|
||||
def link(self, url: str, text: str, url_id: str = ...) -> str: ...
|
||||
@property
|
||||
def stream(self) -> IO[str]: ...
|
||||
@property
|
||||
def number_of_colors(self) -> int: ...
|
||||
@number_of_colors.setter
|
||||
def number_of_colors(self, value: int) -> None: ...
|
||||
@property
|
||||
def color_distance_algorithm(self) -> str: ...
|
||||
@color_distance_algorithm.setter
|
||||
def color_distance_algorithm(self, value: str) -> None: ...
|
||||
def ljust(
|
||||
self, text: str, width: Optional[int] = ..., fillchar: str = ...
|
||||
) -> str: ...
|
||||
def rjust(
|
||||
self, text: str, width: Optional[int] = ..., fillchar: str = ...
|
||||
) -> str: ...
|
||||
def center(
|
||||
self, text: str, width: Optional[int] = ..., fillchar: str = ...
|
||||
) -> str: ...
|
||||
def truncate(self, text: str, width: Optional[int] = ...) -> str: ...
|
||||
def length(self, text: str) -> int: ...
|
||||
def strip(self, text: str, chars: Optional[str] = ...) -> str: ...
|
||||
def rstrip(self, text: str, chars: Optional[str] = ...) -> str: ...
|
||||
def lstrip(self, text: str, chars: Optional[str] = ...) -> str: ...
|
||||
def strip_seqs(self, text: str) -> str: ...
|
||||
def split_seqs(self, text: str, maxsplit: int) -> List[str]: ...
|
||||
def wrap(
|
||||
self, text: str, width: Optional[int] = ..., **kwargs: Any
|
||||
) -> List[str]: ...
|
||||
def getch(self) -> str: ...
|
||||
def ungetch(self, text: str) -> None: ...
|
||||
def kbhit(self, timeout: Optional[float] = ...) -> bool: ...
|
||||
def cbreak(self) -> ContextManager[None]: ...
|
||||
def raw(self) -> ContextManager[None]: ...
|
||||
def keypad(self) -> ContextManager[None]: ...
|
||||
def inkey(
|
||||
self, timeout: Optional[float] = ..., esc_delay: float = ...
|
||||
) -> Keystroke: ...
|
||||
|
||||
class WINSZ: ...
|
|
@ -0,0 +1,163 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Module containing Windows version of :class:`Terminal`."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
# std imports
|
||||
import time
|
||||
import msvcrt # pylint: disable=import-error
|
||||
import contextlib
|
||||
|
||||
# 3rd party
|
||||
from jinxed import win32 # pylint: disable=import-error
|
||||
|
||||
# local
|
||||
from .terminal import WINSZ
|
||||
from .terminal import Terminal as _Terminal
|
||||
|
||||
|
||||
class Terminal(_Terminal):
|
||||
"""Windows subclass of :class:`Terminal`."""
|
||||
|
||||
def getch(self):
|
||||
r"""
|
||||
Read, decode, and return the next byte from the keyboard stream.
|
||||
|
||||
:rtype: unicode
|
||||
:returns: a single unicode character, or ``u''`` if a multi-byte
|
||||
sequence has not yet been fully received.
|
||||
|
||||
For versions of Windows 10.0.10586 and later, the console is expected
|
||||
to be in ENABLE_VIRTUAL_TERMINAL_INPUT mode and the default method is
|
||||
called.
|
||||
|
||||
For older versions of Windows, msvcrt.getwch() is used. If the received
|
||||
character is ``\x00`` or ``\xe0``, the next character is
|
||||
automatically retrieved.
|
||||
"""
|
||||
if win32.VTMODE_SUPPORTED:
|
||||
return super(Terminal, self).getch()
|
||||
|
||||
rtn = msvcrt.getwch()
|
||||
if rtn in ('\x00', '\xe0'):
|
||||
rtn += msvcrt.getwch()
|
||||
return rtn
|
||||
|
||||
def kbhit(self, timeout=None):
|
||||
"""
|
||||
Return whether a keypress has been detected on the keyboard.
|
||||
|
||||
This method is used by :meth:`inkey` to determine if a byte may
|
||||
be read using :meth:`getch` without blocking. This is implemented
|
||||
by wrapping msvcrt.kbhit() in a timeout.
|
||||
|
||||
:arg float timeout: When ``timeout`` is 0, this call is
|
||||
non-blocking, otherwise blocking indefinitely until keypress
|
||||
is detected when None (default). When ``timeout`` is a
|
||||
positive number, returns after ``timeout`` seconds have
|
||||
elapsed (float).
|
||||
:rtype: bool
|
||||
:returns: True if a keypress is awaiting to be read on the keyboard
|
||||
attached to this terminal.
|
||||
"""
|
||||
end = time.time() + (timeout or 0)
|
||||
while True:
|
||||
|
||||
if msvcrt.kbhit():
|
||||
return True
|
||||
|
||||
if timeout is not None and end < time.time():
|
||||
break
|
||||
|
||||
time.sleep(0.01) # Sleep to reduce CPU load
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _winsize(fd):
|
||||
"""
|
||||
Return named tuple describing size of the terminal by ``fd``.
|
||||
|
||||
:arg int fd: file descriptor queries for its window size.
|
||||
:rtype: WINSZ
|
||||
:returns: named tuple describing size of the terminal
|
||||
|
||||
WINSZ is a :class:`collections.namedtuple` instance, whose structure
|
||||
directly maps to the return value of the :const:`termios.TIOCGWINSZ`
|
||||
ioctl return value. The return parameters are:
|
||||
|
||||
- ``ws_row``: width of terminal by its number of character cells.
|
||||
- ``ws_col``: height of terminal by its number of character cells.
|
||||
- ``ws_xpixel``: width of terminal by pixels (not accurate).
|
||||
- ``ws_ypixel``: height of terminal by pixels (not accurate).
|
||||
"""
|
||||
window = win32.get_terminal_size(fd)
|
||||
return WINSZ(ws_row=window.lines, ws_col=window.columns,
|
||||
ws_xpixel=0, ws_ypixel=0)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def cbreak(self):
|
||||
"""
|
||||
Allow each keystroke to be read immediately after it is pressed.
|
||||
|
||||
This is a context manager for ``jinxed.w32.setcbreak()``.
|
||||
|
||||
.. note:: You must explicitly print any user input you would like
|
||||
displayed. If you provide any kind of editing, you must handle
|
||||
backspace and other line-editing control functions in this mode
|
||||
as well!
|
||||
|
||||
**Normally**, characters received from the keyboard cannot be read
|
||||
by Python until the *Return* key is pressed. Also known as *cooked* or
|
||||
*canonical input* mode, it allows the tty driver to provide
|
||||
line-editing before shuttling the input to your program and is the
|
||||
(implicit) default terminal mode set by most unix shells before
|
||||
executing programs.
|
||||
"""
|
||||
if self._keyboard_fd is not None:
|
||||
|
||||
filehandle = msvcrt.get_osfhandle(self._keyboard_fd)
|
||||
|
||||
# Save current terminal mode:
|
||||
save_mode = win32.get_console_mode(filehandle)
|
||||
save_line_buffered = self._line_buffered
|
||||
win32.setcbreak(filehandle)
|
||||
try:
|
||||
self._line_buffered = False
|
||||
yield
|
||||
finally:
|
||||
win32.set_console_mode(filehandle, save_mode)
|
||||
self._line_buffered = save_line_buffered
|
||||
|
||||
else:
|
||||
yield
|
||||
|
||||
@contextlib.contextmanager
|
||||
def raw(self):
|
||||
"""
|
||||
A context manager for ``jinxed.w32.setcbreak()``.
|
||||
|
||||
Although both :meth:`break` and :meth:`raw` modes allow each keystroke
|
||||
to be read immediately after it is pressed, Raw mode disables
|
||||
processing of input and output.
|
||||
|
||||
In cbreak mode, special input characters such as ``^C`` are
|
||||
interpreted by the terminal driver and excluded from the stdin stream.
|
||||
In raw mode these values are receive by the :meth:`inkey` method.
|
||||
"""
|
||||
if self._keyboard_fd is not None:
|
||||
|
||||
filehandle = msvcrt.get_osfhandle(self._keyboard_fd)
|
||||
|
||||
# Save current terminal mode:
|
||||
save_mode = win32.get_console_mode(filehandle)
|
||||
save_line_buffered = self._line_buffered
|
||||
win32.setraw(filehandle)
|
||||
try:
|
||||
self._line_buffered = False
|
||||
yield
|
||||
finally:
|
||||
win32.set_console_mode(filehandle, save_mode)
|
||||
self._line_buffered = save_line_buffered
|
||||
|
||||
else:
|
||||
yield
|
|
@ -0,0 +1,11 @@
|
|||
# std imports
|
||||
from typing import Optional, ContextManager
|
||||
|
||||
# local
|
||||
from .terminal import Terminal as _Terminal
|
||||
|
||||
class Terminal(_Terminal):
|
||||
def getch(self) -> str: ...
|
||||
def kbhit(self, timeout: Optional[float] = ...) -> bool: ...
|
||||
def cbreak(self) -> ContextManager[None]: ...
|
||||
def raw(self) -> ContextManager[None]: ...
|
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -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,,
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
jinxed
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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`"""
|
|
@ -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
|
|
@ -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'
|
||||
}
|
|
@ -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
|
||||
]
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -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'
|
|
@ -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'
|
|
@ -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
|
|
@ -18,6 +18,14 @@ yarl = ">=1.0,<2.0"
|
|||
[package.extras]
|
||||
speedups = ["aiodns", "brotlipy", "cchardet"]
|
||||
|
||||
[[package]]
|
||||
name = "ansicon"
|
||||
version = "1.89.0"
|
||||
description = "Python wrapper for loading Jason Hood's ANSICON"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "appdirs"
|
||||
version = "1.4.4"
|
||||
|
@ -48,6 +56,19 @@ dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.int
|
|||
docs = ["sphinx", "zope.interface"]
|
||||
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||
|
||||
[[package]]
|
||||
name = "blessed"
|
||||
version = "1.19.1"
|
||||
description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""}
|
||||
six = ">=1.9.0"
|
||||
wcwidth = ">=0.1.4"
|
||||
|
||||
[[package]]
|
||||
name = "blessings"
|
||||
version = "1.7"
|
||||
|
@ -277,6 +298,17 @@ MarkupSafe = ">=0.23"
|
|||
[package.extras]
|
||||
i18n = ["Babel (>=0.8)"]
|
||||
|
||||
[[package]]
|
||||
name = "jinxed"
|
||||
version = "1.2.0"
|
||||
description = "Jinxed Terminal Library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
ansicon = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "jsmin"
|
||||
version = "2.1.0"
|
||||
|
@ -709,6 +741,14 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.5"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "wheel"
|
||||
version = "0.37.0"
|
||||
|
@ -760,7 +800,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.6"
|
||||
content-hash = "a12185410cebae037b0b16a9f8a3b99e1069c4f8d55157c48e15cc3f14233228"
|
||||
content-hash = "d970a7f50c39dcde79cad81f51e07fcbe19e697c2e778f62b53ebc95bbb4baae"
|
||||
|
||||
[metadata.files]
|
||||
aiohttp = [
|
||||
|
@ -802,6 +842,10 @@ aiohttp = [
|
|||
{file = "aiohttp-3.7.4.post0-cp39-cp39-win_amd64.whl", hash = "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe"},
|
||||
{file = "aiohttp-3.7.4.post0.tar.gz", hash = "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf"},
|
||||
]
|
||||
ansicon = [
|
||||
{file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"},
|
||||
{file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"},
|
||||
]
|
||||
appdirs = [
|
||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
|
@ -814,6 +858,10 @@ attrs = [
|
|||
{file = "attrs-19.2.0-py2.py3-none-any.whl", hash = "sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2"},
|
||||
{file = "attrs-19.2.0.tar.gz", hash = "sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396"},
|
||||
]
|
||||
blessed = [
|
||||
{file = "blessed-1.19.1-py2.py3-none-any.whl", hash = "sha256:63b8554ae2e0e7f43749b6715c734cc8f3883010a809bf16790102563e6cf25b"},
|
||||
{file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"},
|
||||
]
|
||||
blessings = [
|
||||
{file = "blessings-1.7-py2-none-any.whl", hash = "sha256:caad5211e7ba5afe04367cdd4cfc68fa886e2e08f6f35e76b7387d2109ccea6e"},
|
||||
{file = "blessings-1.7-py3-none-any.whl", hash = "sha256:b1fdd7e7a675295630f9ae71527a8ebc10bfefa236b3d6aa4932ee4462c17ba3"},
|
||||
|
@ -900,6 +948,10 @@ jinja2 = [
|
|||
{file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"},
|
||||
{file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"},
|
||||
]
|
||||
jinxed = [
|
||||
{file = "jinxed-1.2.0-py2.py3-none-any.whl", hash = "sha256:cfc2b2e4e3b4326954d546ba6d6b9a7a796ddcb0aef8d03161d005177eb0d48b"},
|
||||
{file = "jinxed-1.2.0.tar.gz", hash = "sha256:032acda92d5c57cd216033cbbd53de731e6ed50deb63eb4781336ca55f72cda5"},
|
||||
]
|
||||
jsmin = [
|
||||
{file = "jsmin-2.1.0.tar.gz", hash = "sha256:5d07bf0251a4128e5e8e8eef603849b6b5741c337bff087731a248f9cc774f56"},
|
||||
]
|
||||
|
@ -1181,6 +1233,10 @@ voluptuous = [
|
|||
{file = "voluptuous-0.12.1-py3-none-any.whl", hash = "sha256:8ace33fcf9e6b1f59406bfaf6b8ec7bcc44266a9f29080b4deb4fe6ff2492386"},
|
||||
{file = "voluptuous-0.12.1.tar.gz", hash = "sha256:663572419281ddfaf4b4197fd4942d181630120fb39b333e3adad70aeb56444b"},
|
||||
]
|
||||
wcwidth = [
|
||||
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||
]
|
||||
wheel = [
|
||||
{file = "wheel-0.37.0-py2.py3-none-any.whl", hash = "sha256:21014b2bd93c6d0034b6ba5d35e4eb284340e09d63c59aef6fc14b0f346146fd"},
|
||||
{file = "wheel-0.37.0.tar.gz", hash = "sha256:e2ef7239991699e3355d54f8e968a21bb940a1dbf34a4d226741e64462516fad"},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
appdirs==1.4.4
|
||||
attrs==19.2.0
|
||||
blessed==1.19.1
|
||||
blessings==1.7
|
||||
cbor2==4.0.1
|
||||
colorama==0.4.5
|
||||
|
|
|
@ -36,6 +36,9 @@ aiohttp==3.7.4.post0; python_version >= "3.6" \
|
|||
--hash=sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9 \
|
||||
--hash=sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe \
|
||||
--hash=sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf
|
||||
ansicon==1.89.0; platform_system == "Windows" and python_version >= "2.7" \
|
||||
--hash=sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec \
|
||||
--hash=sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1
|
||||
appdirs==1.4.4 \
|
||||
--hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 \
|
||||
--hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41
|
||||
|
@ -45,6 +48,9 @@ async-timeout==3.0.1; python_full_version >= "3.5.3" and python_version >= "3.6"
|
|||
attrs==19.2.0; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \
|
||||
--hash=sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2 \
|
||||
--hash=sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396
|
||||
blessed==1.19.1; python_version >= "2.7" \
|
||||
--hash=sha256:63b8554ae2e0e7f43749b6715c734cc8f3883010a809bf16790102563e6cf25b \
|
||||
--hash=sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc
|
||||
blessings==1.7; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \
|
||||
--hash=sha256:caad5211e7ba5afe04367cdd4cfc68fa886e2e08f6f35e76b7387d2109ccea6e \
|
||||
--hash=sha256:b1fdd7e7a675295630f9ae71527a8ebc10bfefa236b3d6aa4932ee4462c17ba3 \
|
||||
|
@ -109,6 +115,9 @@ iso8601==0.1.14; python_version <= "3.6" \
|
|||
jinja2==2.11.3; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419 \
|
||||
--hash=sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6
|
||||
jinxed==1.2.0; platform_system == "Windows" and python_version >= "2.7" \
|
||||
--hash=sha256:cfc2b2e4e3b4326954d546ba6d6b9a7a796ddcb0aef8d03161d005177eb0d48b \
|
||||
--hash=sha256:032acda92d5c57cd216033cbbd53de731e6ed50deb63eb4781336ca55f72cda5
|
||||
jsmin==2.1.0 \
|
||||
--hash=sha256:5d07bf0251a4128e5e8e8eef603849b6b5741c337bff087731a248f9cc774f56
|
||||
json-e==2.7.0 \
|
||||
|
@ -352,6 +361,9 @@ urllib3==1.26.0; (python_version >= "2.7" and python_full_version < "3.0.0") or
|
|||
voluptuous==0.12.1 \
|
||||
--hash=sha256:8ace33fcf9e6b1f59406bfaf6b8ec7bcc44266a9f29080b4deb4fe6ff2492386 \
|
||||
--hash=sha256:663572419281ddfaf4b4197fd4942d181630120fb39b333e3adad70aeb56444b
|
||||
wcwidth==0.2.5; python_version >= "2.7" \
|
||||
--hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \
|
||||
--hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83
|
||||
wheel==0.37.0; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") \
|
||||
--hash=sha256:21014b2bd93c6d0034b6ba5d35e4eb284340e09d63c59aef6fc14b0f346146fd \
|
||||
--hash=sha256:e2ef7239991699e3355d54f8e968a21bb940a1dbf34a4d226741e64462516fad
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jeff Quast <contact@jeffquast.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
for any purpose and without fee is hereby granted. The author
|
||||
disclaims all warranties with regard to this software.
|
|
@ -0,0 +1,309 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: wcwidth
|
||||
Version: 0.2.5
|
||||
Summary: Measures the displayed width of unicode strings in a terminal
|
||||
Home-page: https://github.com/jquast/wcwidth
|
||||
Author: Jeff Quast
|
||||
Author-email: contact@jeffquast.com
|
||||
License: MIT
|
||||
Keywords: cjk,combining,console,eastasian,emojiemulator,terminal,unicode,wcswidth,wcwidth,xterm
|
||||
Platform: UNKNOWN
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: POSIX
|
||||
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: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: Software Development :: Localization
|
||||
Classifier: Topic :: Software Development :: Internationalization
|
||||
Classifier: Topic :: Terminals
|
||||
Requires-Dist: backports.functools-lru-cache (>=1.2.1) ; python_version < "3.2"
|
||||
|
||||
|pypi_downloads| |codecov| |license|
|
||||
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
This library is mainly for CLI programs that carefully produce output for
|
||||
Terminals, or make pretend to be an emulator.
|
||||
|
||||
**Problem Statement**: The printable length of *most* strings are equal to the
|
||||
number of cells they occupy on the screen ``1 charater : 1 cell``. However,
|
||||
there are categories of characters that *occupy 2 cells* (full-wide), and
|
||||
others that *occupy 0* cells (zero-width).
|
||||
|
||||
**Solution**: POSIX.1-2001 and POSIX.1-2008 conforming systems provide
|
||||
`wcwidth(3)`_ and `wcswidth(3)`_ C functions of which this python module's
|
||||
functions precisely copy. *These functions return the number of cells a
|
||||
unicode string is expected to occupy.*
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The stable version of this package is maintained on pypi, install using pip::
|
||||
|
||||
pip install wcwidth
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
**Problem**: given the following phrase (Japanese),
|
||||
|
||||
>>> text = u'コンニチハ'
|
||||
|
||||
Python **incorrectly** uses the *string length* of 5 codepoints rather than the
|
||||
*printible length* of 10 cells, so that when using the `rjust` function, the
|
||||
output length is wrong::
|
||||
|
||||
>>> print(len('コンニチハ'))
|
||||
5
|
||||
|
||||
>>> print('コンニチハ'.rjust(20, '_'))
|
||||
_____コンニチハ
|
||||
|
||||
By defining our own "rjust" function that uses wcwidth, we can correct this::
|
||||
|
||||
>>> def wc_rjust(text, length, padding=' '):
|
||||
... from wcwidth import wcswidth
|
||||
... return padding * max(0, (length - wcswidth(text))) + text
|
||||
...
|
||||
|
||||
Our **Solution** uses wcswidth to determine the string length correctly::
|
||||
|
||||
>>> from wcwidth import wcswidth
|
||||
>>> print(wcswidth('コンニチハ'))
|
||||
10
|
||||
|
||||
>>> print(wc_rjust('コンニチハ', 20, '_'))
|
||||
__________コンニチハ
|
||||
|
||||
|
||||
Choosing a Version
|
||||
------------------
|
||||
|
||||
Export an environment variable, ``UNICODE_VERSION``. This should be done by
|
||||
*terminal emulators* or those developers experimenting with authoring one of
|
||||
their own, from shell::
|
||||
|
||||
$ export UNICODE_VERSION=13.0
|
||||
|
||||
If unspecified, the latest version is used. If your Terminal Emulator does not
|
||||
export this variable, you can use the `jquast/ucs-detect`_ utility to
|
||||
automatically detect and export it to your shell.
|
||||
|
||||
wcwidth, wcswidth
|
||||
-----------------
|
||||
Use function ``wcwidth()`` to determine the length of a *single unicode
|
||||
character*, and ``wcswidth()`` to determine the length of many, a *string
|
||||
of unicode characters*.
|
||||
|
||||
Briefly, return values of function ``wcwidth()`` are:
|
||||
|
||||
``-1``
|
||||
Indeterminate (not printable).
|
||||
|
||||
``0``
|
||||
Does not advance the cursor, such as NULL or Combining.
|
||||
|
||||
``2``
|
||||
Characters of category East Asian Wide (W) or East Asian
|
||||
Full-width (F) which are displayed using two terminal cells.
|
||||
|
||||
``1``
|
||||
All others.
|
||||
|
||||
Function ``wcswidth()`` simply returns the sum of all values for each character
|
||||
along a string, or ``-1`` when it occurs anywhere along a string.
|
||||
|
||||
Full API Documentation at http://wcwidth.readthedocs.org
|
||||
|
||||
==========
|
||||
Developing
|
||||
==========
|
||||
|
||||
Install wcwidth in editable mode::
|
||||
|
||||
pip install -e.
|
||||
|
||||
Execute unit tests using tox_::
|
||||
|
||||
tox
|
||||
|
||||
Regenerate python code tables from latest Unicode Specification data files::
|
||||
|
||||
tox -eupdate
|
||||
|
||||
Supplementary tools for browsing and testing terminals for wide unicode
|
||||
characters are found in the `bin/`_ of this project's source code. Just ensure
|
||||
to first ``pip install -erequirements-develop.txt`` from this projects main
|
||||
folder. For example, an interactive browser for testing::
|
||||
|
||||
./bin/wcwidth-browser.py
|
||||
|
||||
Uses
|
||||
----
|
||||
|
||||
This library is used in:
|
||||
|
||||
- `jquast/blessed`_: a thin, practical wrapper around terminal capabilities in
|
||||
Python.
|
||||
|
||||
- `jonathanslenders/python-prompt-toolkit`_: a Library for building powerful
|
||||
interactive command lines in Python.
|
||||
|
||||
- `dbcli/pgcli`_: Postgres CLI with autocompletion and syntax highlighting.
|
||||
|
||||
- `thomasballinger/curtsies`_: a Curses-like terminal wrapper with a display
|
||||
based on compositing 2d arrays of text.
|
||||
|
||||
- `selectel/pyte`_: Simple VTXXX-compatible linux terminal emulator.
|
||||
|
||||
- `astanin/python-tabulate`_: Pretty-print tabular data in Python, a library
|
||||
and a command-line utility.
|
||||
|
||||
- `LuminosoInsight/python-ftfy`_: Fixes mojibake and other glitches in Unicode
|
||||
text.
|
||||
|
||||
- `nbedos/termtosvg`_: Terminal recorder that renders sessions as SVG
|
||||
animations.
|
||||
|
||||
- `peterbrittain/asciimatics`_: Package to help people create full-screen text
|
||||
UIs.
|
||||
|
||||
Other Languages
|
||||
---------------
|
||||
|
||||
- `timoxley/wcwidth`_: JavaScript
|
||||
- `janlelis/unicode-display_width`_: Ruby
|
||||
- `alecrabbit/php-wcwidth`_: PHP
|
||||
- `Text::CharWidth`_: Perl
|
||||
- `bluebear94/Terminal-WCWidth`: Perl 6
|
||||
- `mattn/go-runewidth`_: Go
|
||||
- `emugel/wcwidth`_: Haxe
|
||||
- `aperezdc/lua-wcwidth`: Lua
|
||||
- `joachimschmidt557/zig-wcwidth`: Zig
|
||||
- `fumiyas/wcwidth-cjk`: `LD_PRELOAD` override
|
||||
- `joshuarubin/wcwidth9`: Unicode version 9 in C
|
||||
|
||||
History
|
||||
-------
|
||||
|
||||
0.2.0 *2020-06-01*
|
||||
* **Enhancement**: Unicode version may be selected by exporting the
|
||||
Environment variable ``UNICODE_VERSION``, such as ``13.0``, or ``6.3.0``.
|
||||
See the `jquast/ucs-detect`_ CLI utility for automatic detection.
|
||||
* **Enhancement**:
|
||||
API Documentation is published to readthedocs.org.
|
||||
* **Updated** tables for *all* Unicode Specifications with files
|
||||
published in a programmatically consumable format, versions 4.1.0
|
||||
through 13.0
|
||||
that are published
|
||||
, versions
|
||||
|
||||
0.1.9 *2020-03-22*
|
||||
* **Performance** optimization by `Avram Lubkin`_, `PR #35`_.
|
||||
* **Updated** tables to Unicode Specification 13.0.0.
|
||||
|
||||
0.1.8 *2020-01-01*
|
||||
* **Updated** tables to Unicode Specification 12.0.0. (`PR #30`_).
|
||||
|
||||
0.1.7 *2016-07-01*
|
||||
* **Updated** tables to Unicode Specification 9.0.0. (`PR #18`_).
|
||||
|
||||
0.1.6 *2016-01-08 Production/Stable*
|
||||
* ``LICENSE`` file now included with distribution.
|
||||
|
||||
0.1.5 *2015-09-13 Alpha*
|
||||
* **Bugfix**:
|
||||
Resolution of "combining_ character width" issue, most especially
|
||||
those that previously returned -1 now often (correctly) return 0.
|
||||
resolved by `Philip Craig`_ via `PR #11`_.
|
||||
* **Deprecated**:
|
||||
The module path ``wcwidth.table_comb`` is no longer available,
|
||||
it has been superseded by module path ``wcwidth.table_zero``.
|
||||
|
||||
0.1.4 *2014-11-20 Pre-Alpha*
|
||||
* **Feature**: ``wcswidth()`` now determines printable length
|
||||
for (most) combining_ characters. The developer's tool
|
||||
`bin/wcwidth-browser.py`_ is improved to display combining_
|
||||
characters when provided the ``--combining`` option
|
||||
(`Thomas Ballinger`_ and `Leta Montopoli`_ `PR #5`_).
|
||||
* **Feature**: added static analysis (prospector_) to testing
|
||||
framework.
|
||||
|
||||
0.1.3 *2014-10-29 Pre-Alpha*
|
||||
* **Bugfix**: 2nd parameter of wcswidth was not honored.
|
||||
(`Thomas Ballinger`_, `PR #4`_).
|
||||
|
||||
0.1.2 *2014-10-28 Pre-Alpha*
|
||||
* **Updated** tables to Unicode Specification 7.0.0.
|
||||
(`Thomas Ballinger`_, `PR #3`_).
|
||||
|
||||
0.1.1 *2014-05-14 Pre-Alpha*
|
||||
* Initial release to pypi, Based on Unicode Specification 6.3.0
|
||||
|
||||
This code was originally derived directly from C code of the same name,
|
||||
whose latest version is available at
|
||||
http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
||||
|
||||
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* for any purpose and without fee is hereby granted. The author
|
||||
* disclaims all warranties with regard to this software.
|
||||
|
||||
.. _`tox`: https://testrun.org/tox/latest/install.html
|
||||
.. _`prospector`: https://github.com/landscapeio/prospector
|
||||
.. _`combining`: https://en.wikipedia.org/wiki/Combining_character
|
||||
.. _`bin/`: https://github.com/jquast/wcwidth/tree/master/bin
|
||||
.. _`bin/wcwidth-browser.py`: https://github.com/jquast/wcwidth/tree/master/bin/wcwidth-browser.py
|
||||
.. _`Thomas Ballinger`: https://github.com/thomasballinger
|
||||
.. _`Leta Montopoli`: https://github.com/lmontopo
|
||||
.. _`Philip Craig`: https://github.com/philipc
|
||||
.. _`PR #3`: https://github.com/jquast/wcwidth/pull/3
|
||||
.. _`PR #4`: https://github.com/jquast/wcwidth/pull/4
|
||||
.. _`PR #5`: https://github.com/jquast/wcwidth/pull/5
|
||||
.. _`PR #11`: https://github.com/jquast/wcwidth/pull/11
|
||||
.. _`PR #18`: https://github.com/jquast/wcwidth/pull/18
|
||||
.. _`PR #30`: https://github.com/jquast/wcwidth/pull/30
|
||||
.. _`PR #35`: https://github.com/jquast/wcwidth/pull/35
|
||||
.. _`jquast/blessed`: https://github.com/jquast/blessed
|
||||
.. _`selectel/pyte`: https://github.com/selectel/pyte
|
||||
.. _`thomasballinger/curtsies`: https://github.com/thomasballinger/curtsies
|
||||
.. _`dbcli/pgcli`: https://github.com/dbcli/pgcli
|
||||
.. _`jonathanslenders/python-prompt-toolkit`: https://github.com/jonathanslenders/python-prompt-toolkit
|
||||
.. _`timoxley/wcwidth`: https://github.com/timoxley/wcwidth
|
||||
.. _`wcwidth(3)`: http://man7.org/linux/man-pages/man3/wcwidth.3.html
|
||||
.. _`wcswidth(3)`: http://man7.org/linux/man-pages/man3/wcswidth.3.html
|
||||
.. _`astanin/python-tabulate`: https://github.com/astanin/python-tabulate
|
||||
.. _`janlelis/unicode-display_width`: https://github.com/janlelis/unicode-display_width
|
||||
.. _`LuminosoInsight/python-ftfy`: https://github.com/LuminosoInsight/python-ftfy
|
||||
.. _`alecrabbit/php-wcwidth`: https://github.com/alecrabbit/php-wcwidth
|
||||
.. _`Text::CharWidth`: https://metacpan.org/pod/Text::CharWidth
|
||||
.. _`bluebear94/Terminal-WCWidth`: https://github.com/bluebear94/Terminal-WCWidth
|
||||
.. _`mattn/go-runewidth`: https://github.com/mattn/go-runewidth
|
||||
.. _`emugel/wcwidth`: https://github.com/emugel/wcwidth
|
||||
.. _`jquast/ucs-detect`: https://github.com/jquast/ucs-detect
|
||||
.. _`Avram Lubkin`: https://github.com/avylove
|
||||
.. _`nbedos/termtosvg`: https://github.com/nbedos/termtosvg
|
||||
.. _`peterbrittain/asciimatics`: https://github.com/peterbrittain/asciimatics
|
||||
.. _`aperezdc/lua-wcwidth`: https://github.com/aperezdc/lua-wcwidth
|
||||
.. _`fumiyas/wcwidth-cjk`: https://github.com/fumiyas/wcwidth-cjk
|
||||
.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi
|
||||
:alt: Downloads
|
||||
:target: https://pypi.org/project/wcwidth/
|
||||
.. |codecov| image:: https://codecov.io/gh/jquast/wcwidth/branch/master/graph/badge.svg
|
||||
:alt: codecov.io Code Coverage
|
||||
:target: https://codecov.io/gh/jquast/wcwidth/
|
||||
.. |license| image:: https://img.shields.io/github/license/jquast/wcwidth.svg
|
||||
:target: https://pypi.python.org/pypi/wcwidth/
|
||||
:alt: MIT License
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
wcwidth/__init__.py,sha256=89fk8q2MPb4clahe_qDVIzlIa0U2872dsE4hEwxC6W8,1557
|
||||
wcwidth/table_wide.py,sha256=0yAEOGX6KIrsm5dUpzG0Jrb4s8wB6c7MC76ndXjLLj8,79422
|
||||
wcwidth/table_zero.py,sha256=w8ym8msWG1R2XhtJXRjUkT1erFIhj8d6YclXXrYoakQ,310230
|
||||
wcwidth/unicode_versions.py,sha256=pmyPU8jPCqNOjOHSVHLedKcWeW-SABSBcJ1EJemQJbo,792
|
||||
wcwidth/version.json,sha256=1zjrg0NodaudGjvcY-Eh-5JnBGKHkmVCIj2L9lN9k-U,202
|
||||
wcwidth/wcwidth.py,sha256=0bgA8U17QyvSHscy5zu1JW7rTWcEadw6HwNNbA9Phvk,14872
|
||||
wcwidth/tests/__init__.py,sha256=v_2uRwUE3hTJkuW656dLrkDiM9al7KL1j_vwGRc0RTM,42
|
||||
wcwidth/tests/test_core.py,sha256=gBaR8b3Vv2Wq1q5vGk9fAT0eW12AaEK5kuzH6fwCO-Q,3886
|
||||
wcwidth-0.2.5.dist-info/LICENSE,sha256=cLmKlaIUTrcK-AF_qMbZXOJH5AhnQ26LxknhN_4T0ho,1322
|
||||
wcwidth-0.2.5.dist-info/METADATA,sha256=K6QVxN6Eq7tMwUYeCeEgAcg0VjFqTrrUPOZL3flmEco,11257
|
||||
wcwidth-0.2.5.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
|
||||
wcwidth-0.2.5.dist-info/top_level.txt,sha256=LLjS8SFiXXuLEcD2BNdFdGhpKWe5opHtvn7KNj9AIRI,8
|
||||
wcwidth-0.2.5.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
||||
wcwidth-0.2.5.dist-info/RECORD,,
|
|
@ -0,0 +1,6 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.34.2)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1 @@
|
|||
wcwidth
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
"""
|
||||
wcwidth module.
|
||||
|
||||
https://github.com/jquast/wcwidth
|
||||
"""
|
||||
# re-export all functions & definitions, even private ones, from top-level
|
||||
# module path, to allow for 'from wcwidth import _private_func'. Of course,
|
||||
# user beware that any _private function may disappear or change signature at
|
||||
# any future version.
|
||||
|
||||
# local
|
||||
from .wcwidth import ZERO_WIDTH # noqa
|
||||
from .wcwidth import (WIDE_EASTASIAN,
|
||||
wcwidth,
|
||||
wcswidth,
|
||||
_bisearch,
|
||||
list_versions,
|
||||
_wcmatch_version,
|
||||
_wcversion_value)
|
||||
|
||||
# The __all__ attribute defines the items exported from statement,
|
||||
# 'from wcwidth import *', but also to say, "This is the public API".
|
||||
__all__ = ('wcwidth', 'wcswidth', 'list_versions')
|
||||
|
||||
# I used to use a _get_package_version() function to use the `pkg_resources'
|
||||
# module to parse the package version from our version.json file, but this blew
|
||||
# some folks up, or more particularly, just the `xonsh' shell.
|
||||
#
|
||||
# Yikes! I always wanted to like xonsh and tried it many times but issues like
|
||||
# these always bit me, too, so I can sympathize -- this version is now manually
|
||||
# kept in sync with version.json to help them out. Shucks, this variable is just
|
||||
# for legacy, from the days before 'pip freeze' was a thing.
|
||||
#
|
||||
# We also used pkg_resources to load unicode version tables from version.json,
|
||||
# generated by bin/update-tables.py, but some environments are unable to
|
||||
# import pkg_resources for one reason or another, yikes!
|
||||
__version__ = '0.2.5'
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,35 @@
|
|||
"""
|
||||
Exports function list_versions() for unicode version level support.
|
||||
|
||||
This code generated by bin/update-tables.py on 2020-06-23 16:03:21.350604.
|
||||
"""
|
||||
|
||||
|
||||
def list_versions():
|
||||
"""
|
||||
Return Unicode version levels supported by this module release.
|
||||
|
||||
Any of the version strings returned may be used as keyword argument
|
||||
``unicode_version`` to the ``wcwidth()`` family of functions.
|
||||
|
||||
:returns: Supported Unicode version numbers in ascending sorted order.
|
||||
:rtype: list[str]
|
||||
"""
|
||||
return (
|
||||
"4.1.0",
|
||||
"5.0.0",
|
||||
"5.1.0",
|
||||
"5.2.0",
|
||||
"6.0.0",
|
||||
"6.1.0",
|
||||
"6.2.0",
|
||||
"6.3.0",
|
||||
"7.0.0",
|
||||
"8.0.0",
|
||||
"9.0.0",
|
||||
"10.0.0",
|
||||
"11.0.0",
|
||||
"12.0.0",
|
||||
"12.1.0",
|
||||
"13.0.0",
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
{"tables": ["4.1.0", "5.0.0", "5.1.0", "5.2.0", "6.0.0", "6.1.0", "6.2.0", "6.3.0", "7.0.0", "8.0.0", "9.0.0", "10.0.0", "11.0.0", "12.0.0", "12.1.0", "13.0.0"], "package": "0.2.4", "default": "8.0.0"}
|
|
@ -0,0 +1,375 @@
|
|||
"""
|
||||
This is a python implementation of wcwidth() and wcswidth().
|
||||
|
||||
https://github.com/jquast/wcwidth
|
||||
|
||||
from Markus Kuhn's C code, retrieved from:
|
||||
|
||||
http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
|
||||
This is an implementation of wcwidth() and wcswidth() (defined in
|
||||
IEEE Std 1002.1-2001) for Unicode.
|
||||
|
||||
http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
|
||||
http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
|
||||
|
||||
In fixed-width output devices, Latin characters all occupy a single
|
||||
"cell" position of equal width, whereas ideographic CJK characters
|
||||
occupy two such cells. Interoperability between terminal-line
|
||||
applications and (teletype-style) character terminals using the
|
||||
UTF-8 encoding requires agreement on which character should advance
|
||||
the cursor by how many cell positions. No established formal
|
||||
standards exist at present on which Unicode character shall occupy
|
||||
how many cell positions on character terminals. These routines are
|
||||
a first attempt of defining such behavior based on simple rules
|
||||
applied to data provided by the Unicode Consortium.
|
||||
|
||||
For some graphical characters, the Unicode standard explicitly
|
||||
defines a character-cell width via the definition of the East Asian
|
||||
FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
|
||||
In all these cases, there is no ambiguity about which width a
|
||||
terminal shall use. For characters in the East Asian Ambiguous (A)
|
||||
class, the width choice depends purely on a preference of backward
|
||||
compatibility with either historic CJK or Western practice.
|
||||
Choosing single-width for these characters is easy to justify as
|
||||
the appropriate long-term solution, as the CJK practice of
|
||||
displaying these characters as double-width comes from historic
|
||||
implementation simplicity (8-bit encoded characters were displayed
|
||||
single-width and 16-bit ones double-width, even for Greek,
|
||||
Cyrillic, etc.) and not any typographic considerations.
|
||||
|
||||
Much less clear is the choice of width for the Not East Asian
|
||||
(Neutral) class. Existing practice does not dictate a width for any
|
||||
of these characters. It would nevertheless make sense
|
||||
typographically to allocate two character cells to characters such
|
||||
as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
|
||||
represented adequately with a single-width glyph. The following
|
||||
routines at present merely assign a single-cell width to all
|
||||
neutral characters, in the interest of simplicity. This is not
|
||||
entirely satisfactory and should be reconsidered before
|
||||
establishing a formal standard in this area. At the moment, the
|
||||
decision which Not East Asian (Neutral) characters should be
|
||||
represented by double-width glyphs cannot yet be answered by
|
||||
applying a simple rule from the Unicode database content. Setting
|
||||
up a proper standard for the behavior of UTF-8 character terminals
|
||||
will require a careful analysis not only of each Unicode character,
|
||||
but also of each presentation form, something the author of these
|
||||
routines has avoided to do so far.
|
||||
|
||||
http://www.unicode.org/unicode/reports/tr11/
|
||||
|
||||
Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
"""
|
||||
from __future__ import division
|
||||
|
||||
# std imports
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
# local
|
||||
from .table_wide import WIDE_EASTASIAN
|
||||
from .table_zero import ZERO_WIDTH
|
||||
from .unicode_versions import list_versions
|
||||
|
||||
try:
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
# lru_cache was added in Python 3.2
|
||||
from backports.functools_lru_cache import lru_cache
|
||||
|
||||
# global cache
|
||||
_UNICODE_CMPTABLE = None
|
||||
_PY3 = (sys.version_info[0] >= 3)
|
||||
|
||||
|
||||
# NOTE: created by hand, there isn't anything identifiable other than
|
||||
# general Cf category code to identify these, and some characters in Cf
|
||||
# category code are of non-zero width.
|
||||
# Also includes some Cc, Mn, Zl, and Zp characters
|
||||
ZERO_WIDTH_CF = set([
|
||||
0, # Null (Cc)
|
||||
0x034F, # Combining grapheme joiner (Mn)
|
||||
0x200B, # Zero width space
|
||||
0x200C, # Zero width non-joiner
|
||||
0x200D, # Zero width joiner
|
||||
0x200E, # Left-to-right mark
|
||||
0x200F, # Right-to-left mark
|
||||
0x2028, # Line separator (Zl)
|
||||
0x2029, # Paragraph separator (Zp)
|
||||
0x202A, # Left-to-right embedding
|
||||
0x202B, # Right-to-left embedding
|
||||
0x202C, # Pop directional formatting
|
||||
0x202D, # Left-to-right override
|
||||
0x202E, # Right-to-left override
|
||||
0x2060, # Word joiner
|
||||
0x2061, # Function application
|
||||
0x2062, # Invisible times
|
||||
0x2063, # Invisible separator
|
||||
])
|
||||
|
||||
|
||||
def _bisearch(ucs, table):
|
||||
"""
|
||||
Auxiliary function for binary search in interval table.
|
||||
|
||||
:arg int ucs: Ordinal value of unicode character.
|
||||
:arg list table: List of starting and ending ranges of ordinal values,
|
||||
in form of ``[(start, end), ...]``.
|
||||
:rtype: int
|
||||
:returns: 1 if ordinal value ucs is found within lookup table, else 0.
|
||||
"""
|
||||
lbound = 0
|
||||
ubound = len(table) - 1
|
||||
|
||||
if ucs < table[0][0] or ucs > table[ubound][1]:
|
||||
return 0
|
||||
while ubound >= lbound:
|
||||
mid = (lbound + ubound) // 2
|
||||
if ucs > table[mid][1]:
|
||||
lbound = mid + 1
|
||||
elif ucs < table[mid][0]:
|
||||
ubound = mid - 1
|
||||
else:
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@lru_cache(maxsize=1000)
|
||||
def wcwidth(wc, unicode_version='auto'):
|
||||
r"""
|
||||
Given one Unicode character, return its printable length on a terminal.
|
||||
|
||||
:param str wc: A single Unicode character.
|
||||
:param str unicode_version: A Unicode version number, such as
|
||||
``'6.0.0'``, the list of available version levels may be
|
||||
listed by pairing function :func:`list_versions`.
|
||||
|
||||
Any version string may be specified without error -- the nearest
|
||||
matching version is selected. When ``latest`` (default), the
|
||||
highest Unicode version level is used.
|
||||
:return: The width, in cells, necessary to display the character of
|
||||
Unicode string character, ``wc``. Returns 0 if the ``wc`` argument has
|
||||
no printable effect on a terminal (such as NUL '\0'), -1 if ``wc`` is
|
||||
not printable, or has an indeterminate effect on the terminal, such as
|
||||
a control character. Otherwise, the number of column positions the
|
||||
character occupies on a graphic terminal (1 or 2) is returned.
|
||||
:rtype: int
|
||||
|
||||
The following have a column width of -1:
|
||||
|
||||
- C0 control characters (U+001 through U+01F).
|
||||
|
||||
- C1 control characters and DEL (U+07F through U+0A0).
|
||||
|
||||
The following have a column width of 0:
|
||||
|
||||
- Non-spacing and enclosing combining characters (general
|
||||
category code Mn or Me in the Unicode database).
|
||||
|
||||
- NULL (``U+0000``).
|
||||
|
||||
- COMBINING GRAPHEME JOINER (``U+034F``).
|
||||
|
||||
- ZERO WIDTH SPACE (``U+200B``) *through*
|
||||
RIGHT-TO-LEFT MARK (``U+200F``).
|
||||
|
||||
- LINE SEPARATOR (``U+2028``) *and*
|
||||
PARAGRAPH SEPARATOR (``U+2029``).
|
||||
|
||||
- LEFT-TO-RIGHT EMBEDDING (``U+202A``) *through*
|
||||
RIGHT-TO-LEFT OVERRIDE (``U+202E``).
|
||||
|
||||
- WORD JOINER (``U+2060``) *through*
|
||||
INVISIBLE SEPARATOR (``U+2063``).
|
||||
|
||||
The following have a column width of 1:
|
||||
|
||||
- SOFT HYPHEN (``U+00AD``).
|
||||
|
||||
- All remaining characters, including all printable ISO 8859-1
|
||||
and WGL4 characters, Unicode control characters, etc.
|
||||
|
||||
The following have a column width of 2:
|
||||
|
||||
- Spacing characters in the East Asian Wide (W) or East Asian
|
||||
Full-width (F) category as defined in Unicode Technical
|
||||
Report #11 have a column width of 2.
|
||||
|
||||
- Some kinds of Emoji or symbols.
|
||||
"""
|
||||
# NOTE: created by hand, there isn't anything identifiable other than
|
||||
# general Cf category code to identify these, and some characters in Cf
|
||||
# category code are of non-zero width.
|
||||
ucs = ord(wc)
|
||||
if ucs in ZERO_WIDTH_CF:
|
||||
return 0
|
||||
|
||||
# C0/C1 control characters
|
||||
if ucs < 32 or 0x07F <= ucs < 0x0A0:
|
||||
return -1
|
||||
|
||||
_unicode_version = _wcmatch_version(unicode_version)
|
||||
|
||||
# combining characters with zero width
|
||||
if _bisearch(ucs, ZERO_WIDTH[_unicode_version]):
|
||||
return 0
|
||||
|
||||
return 1 + _bisearch(ucs, WIDE_EASTASIAN[_unicode_version])
|
||||
|
||||
|
||||
def wcswidth(pwcs, n=None, unicode_version='auto'):
|
||||
"""
|
||||
Given a unicode string, return its printable length on a terminal.
|
||||
|
||||
:param str pwcs: Measure width of given unicode string.
|
||||
:param int n: When ``n`` is None (default), return the length of the
|
||||
entire string, otherwise width the first ``n`` characters specified.
|
||||
:param str unicode_version: An explicit definition of the unicode version
|
||||
level to use for determination, may be ``auto`` (default), which uses
|
||||
the Environment Variable, ``UNICODE_VERSION`` if defined, or the latest
|
||||
available unicode version, otherwise.
|
||||
:rtype: int
|
||||
:returns: The width, in cells, necessary to display the first ``n``
|
||||
characters of the unicode string ``pwcs``. Returns ``-1`` if
|
||||
a non-printable character is encountered.
|
||||
"""
|
||||
# pylint: disable=C0103
|
||||
# Invalid argument name "n"
|
||||
|
||||
end = len(pwcs) if n is None else n
|
||||
idx = slice(0, end)
|
||||
width = 0
|
||||
for char in pwcs[idx]:
|
||||
wcw = wcwidth(char, unicode_version)
|
||||
if wcw < 0:
|
||||
return -1
|
||||
width += wcw
|
||||
return width
|
||||
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def _wcversion_value(ver_string):
|
||||
"""
|
||||
Integer-mapped value of given dotted version string.
|
||||
|
||||
:param str ver_string: Unicode version string, of form ``n.n.n``.
|
||||
:rtype: tuple(int)
|
||||
:returns: tuple of digit tuples, ``tuple(int, [...])``.
|
||||
"""
|
||||
retval = tuple(map(int, (ver_string.split('.'))))
|
||||
return retval
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def _wcmatch_version(given_version):
|
||||
"""
|
||||
Return nearest matching supported Unicode version level.
|
||||
|
||||
If an exact match is not determined, the nearest lowest version level is
|
||||
returned after a warning is emitted. For example, given supported levels
|
||||
``4.1.0`` and ``5.0.0``, and a version string of ``4.9.9``, then ``4.1.0``
|
||||
is selected and returned:
|
||||
|
||||
>>> _wcmatch_version('4.9.9')
|
||||
'4.1.0'
|
||||
>>> _wcmatch_version('8.0')
|
||||
'8.0.0'
|
||||
>>> _wcmatch_version('1')
|
||||
'4.1.0'
|
||||
|
||||
:param str given_version: given version for compare, may be ``auto``
|
||||
(default), to select Unicode Version from Environment Variable,
|
||||
``UNICODE_VERSION``. If the environment variable is not set, then the
|
||||
latest is used.
|
||||
:rtype: str
|
||||
:returns: unicode string, or non-unicode ``str`` type for python 2
|
||||
when given ``version`` is also type ``str``.
|
||||
"""
|
||||
# Design note: the choice to return the same type that is given certainly
|
||||
# complicates it for python 2 str-type, but allows us to define an api that
|
||||
# to use 'string-type', for unicode version level definitions, so all of our
|
||||
# example code works with all versions of python. That, along with the
|
||||
# string-to-numeric and comparisons of earliest, latest, matching, or
|
||||
# nearest, greatly complicates this function.
|
||||
_return_str = not _PY3 and isinstance(given_version, str)
|
||||
|
||||
if _return_str:
|
||||
unicode_versions = [ucs.encode() for ucs in list_versions()]
|
||||
else:
|
||||
unicode_versions = list_versions()
|
||||
latest_version = unicode_versions[-1]
|
||||
|
||||
if given_version in (u'auto', 'auto'):
|
||||
given_version = os.environ.get(
|
||||
'UNICODE_VERSION',
|
||||
'latest' if not _return_str else latest_version.encode())
|
||||
|
||||
if given_version in (u'latest', 'latest'):
|
||||
# default match, when given as 'latest', use the most latest unicode
|
||||
# version specification level supported.
|
||||
return latest_version if not _return_str else latest_version.encode()
|
||||
|
||||
if given_version in unicode_versions:
|
||||
# exact match, downstream has specified an explicit matching version
|
||||
# matching any value of list_versions().
|
||||
return given_version if not _return_str else given_version.encode()
|
||||
|
||||
# The user's version is not supported by ours. We return the newest unicode
|
||||
# version level that we support below their given value.
|
||||
try:
|
||||
cmp_given = _wcversion_value(given_version)
|
||||
|
||||
except ValueError:
|
||||
# submitted value raises ValueError in int(), warn and use latest.
|
||||
warnings.warn("UNICODE_VERSION value, {given_version!r}, is invalid. "
|
||||
"Value should be in form of `integer[.]+', the latest "
|
||||
"supported unicode version {latest_version!r} has been "
|
||||
"inferred.".format(given_version=given_version,
|
||||
latest_version=latest_version))
|
||||
return latest_version if not _return_str else latest_version.encode()
|
||||
|
||||
# given version is less than any available version, return earliest
|
||||
# version.
|
||||
earliest_version = unicode_versions[0]
|
||||
cmp_earliest_version = _wcversion_value(earliest_version)
|
||||
|
||||
if cmp_given <= cmp_earliest_version:
|
||||
# this probably isn't what you wanted, the oldest wcwidth.c you will
|
||||
# find in the wild is likely version 5 or 6, which we both support,
|
||||
# but it's better than not saying anything at all.
|
||||
warnings.warn("UNICODE_VERSION value, {given_version!r}, is lower "
|
||||
"than any available unicode version. Returning lowest "
|
||||
"version level, {earliest_version!r}".format(
|
||||
given_version=given_version,
|
||||
earliest_version=earliest_version))
|
||||
return earliest_version if not _return_str else earliest_version.encode()
|
||||
|
||||
# create list of versions which are less than our equal to given version,
|
||||
# and return the tail value, which is the highest level we may support,
|
||||
# or the latest value we support, when completely unmatched or higher
|
||||
# than any supported version.
|
||||
#
|
||||
# function will never complete, always returns.
|
||||
for idx, unicode_version in enumerate(unicode_versions):
|
||||
# look ahead to next value
|
||||
try:
|
||||
cmp_next_version = _wcversion_value(unicode_versions[idx + 1])
|
||||
except IndexError:
|
||||
# at end of list, return latest version
|
||||
return latest_version if not _return_str else latest_version.encode()
|
||||
|
||||
# Maybe our given version has less parts, as in tuple(8, 0), than the
|
||||
# next compare version tuple(8, 0, 0). Test for an exact match by
|
||||
# comparison of only the leading dotted piece(s): (8, 0) == (8, 0).
|
||||
if cmp_given == cmp_next_version[:len(cmp_given)]:
|
||||
return unicode_versions[idx + 1]
|
||||
|
||||
# Or, if any next value is greater than our given support level
|
||||
# version, return the current value in index. Even though it must
|
||||
# be less than the given value, its our closest possible match. That
|
||||
# is, 4.1 is returned for given 4.9.9, where 4.1 and 5.0 are available.
|
||||
if cmp_next_version > cmp_given:
|
||||
return unicode_version
|
||||
assert False, ("Code path unreachable", given_version, unicode_versions)
|
Загрузка…
Ссылка в новой задаче