Release v2.1.1
|
@ -2,3 +2,5 @@
|
|||
.idea
|
||||
neutrino_test
|
||||
|
||||
/bin
|
||||
recovery
|
||||
|
|
9
BUILD.md
|
@ -1,4 +1,4 @@
|
|||
# Building and Auditing
|
||||
## Building for Use
|
||||
|
||||
To build the tool locally and run it, you must:
|
||||
|
||||
|
@ -16,7 +16,12 @@ To build the tool locally and run it, you must:
|
|||
go run -mod=vendor . -- <path to your Emergency Kit PDF>
|
||||
```
|
||||
|
||||
To build the tool in all its variants and verify the checksums for the provided binaries, you need to:
|
||||
This will take some time, as all dependencies must be compiled.
|
||||
|
||||
## Reproducible Building for Verification
|
||||
|
||||
Our builds can be reproduced using Docker. To build all variants and verify the checksums for
|
||||
the binaries we provide, you need to:
|
||||
|
||||
1. Install the [Docker](https://www.docker.com/) toolchain and start the daemon.
|
||||
2. Run this command:
|
||||
|
|
67
README.md
|
@ -1,10 +1,9 @@
|
|||
![muun](https://muun.com/images/github-banner-v2.png)
|
||||
|
||||
## Recovery Tool
|
||||
|
||||
Welcome!
|
||||
|
||||
You can use this tool to transfer all funds out of your Muun account to an address of your choosing.
|
||||
You can use this Recovery Tool to transfer all funds out of your Muun account to an address
|
||||
of your choosing.
|
||||
|
||||
![](readme/demo.gif)
|
||||
|
||||
|
@ -14,40 +13,66 @@ control over their own money. Bitcoin has finally made this possible.
|
|||
|
||||
## Usage
|
||||
|
||||
Download the appropriate binary in the following table, according to your operating system and
|
||||
architecture.
|
||||
Download the appropriate binary from the following table (or see [`BUILD.md`](BUILD.md) to build it yourself),
|
||||
and follow the instructions below.
|
||||
|
||||
| System | Checksum | Link |
|
||||
| --- | --- | --- |
|
||||
| Linux 32-bit | `65c0e27bcff10210f5637a8b9f95ffd8c932d258c21d23d5d9da40ba091864a3` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-linux32) |
|
||||
| Linux 64-bit | `596c819d22501e267385325dd2bba7e5260f711eb3d210c468a606699c8d8369` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-linux64) |
|
||||
| Windows 32-bit | `897ff4db5ccc7f5b37c9c479f018b5ba4a98a243137f186fbf4b96138eff6adc` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-windows32.exe) |
|
||||
| Windows 64-bit | `c03e981119c18270d517d74691283fd3e4d57460d1bf02189c7552b8daa06625` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-windows64.exe) |
|
||||
| MacOS 64-bit | `c5b5d0f65f6b0a1a98bcbf405b50a691b33c347b06b02af98d3350bddb9353f3` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-macos64) |
|
||||
| Linux 32-bit | `4d93d4815e865b21e31e1060fcc5311b380a4ba2d0d53a6fb952850927019d8b` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-linux32) |
|
||||
| Linux 64-bit | `cc9ac14315a0d8b9755b274e1b31f7fb2e16c25100af83f2f54af9be8e0af901` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-linux64) |
|
||||
| Windows 32-bit | `081955009638c596af7193daaf8aae885dea12110f7620f3559bdf611224e393` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-windows32.exe) |
|
||||
| Windows 64-bit | `4abbae9e94855e5cbf2ec44896671f26188128b3b0fdc8954cc01ba6dc533754` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-windows64.exe) |
|
||||
| MacOS 64-bit | `af245b78175d74f315af339eebfe75d495d70cd80b038fd5f00f05d7247651b9` | [Download](https://raw.githubusercontent.com/muun/recovery/master/bin/recovery-tool-macos64) |
|
||||
|
||||
Once you have that, run:
|
||||
### Windows
|
||||
|
||||
Open the downloaded file. You'll be warned that the executable is not from a Microsoft-verified
|
||||
source. Click `More info`, and then `Run anyway`.
|
||||
|
||||
|
||||
### MacOS
|
||||
|
||||
Download the file to a known location (say `Downloads` in your Home directory), then open a terminal
|
||||
and run:
|
||||
|
||||
```
|
||||
chmod +x recovery-tool
|
||||
./recovery-tool <path to your Emergency Kit PDF>
|
||||
cd ~/Downloads
|
||||
chmod +x recovery-tool-macos64
|
||||
./recovery-tool-macos64 <path to your Emergency Kit PDF>
|
||||
```
|
||||
|
||||
The process takes only a few minutes (depending on your connection).
|
||||
If you attempt to open the file directly, MacOS will block you from using it.
|
||||
|
||||
If you have any questions, we'll be happy to answer them. Contact us at support@muun.com
|
||||
### Linux
|
||||
|
||||
## Auditing
|
||||
Download the file to a known location (say `Downloads` in your Home directory), then open a terminal
|
||||
and run:
|
||||
|
||||
This tool is open-sourced so that auditors can dive into the code, and verify it to their benefit
|
||||
and everyone else's. We encourage people with the technical knowledge to do this.
|
||||
```
|
||||
cd ~/Downloads
|
||||
chmod +x recovery-tool-linux64
|
||||
./recovery-tool-linux64 <path to your Emergency Kit PDF>
|
||||
```
|
||||
|
||||
See `BUILD.md` for detailed instructions.
|
||||
Use the `linux32` binary if appropriate.
|
||||
|
||||
## Questions
|
||||
### Questions?
|
||||
|
||||
If you have any questions, we'll be happy to answer them. Contact us at contact@muun.com
|
||||
If you have any questions, we'll be happy to answer them. Contact us at [support@muun.com](mailto:support@muun.com).
|
||||
|
||||
|
||||
## Auditing and Veryfing
|
||||
|
||||
This tool is open-sourced so that auditors can inspect the code, build their own binaries and
|
||||
verify them to their benefit and everyone else's. We encourage people with the technical knowledge
|
||||
to do this.
|
||||
|
||||
To audit the source code, we suggest you start at `main.go` and navigate your way from there. We
|
||||
always work to improve code quality and readability with each release, so that auditing is easier
|
||||
and more effective.
|
||||
|
||||
To build and verify the reproducible binaries we provide, see [`BUILD.md`](BUILD.md).
|
||||
|
||||
## Responsible Disclosure
|
||||
|
||||
Send us an email to report any security related bugs or vulnerabilities at [security@muun.com](mailto:security@muun.com).
|
||||
|
|
2
go.mod
|
@ -5,7 +5,7 @@ go 1.12
|
|||
require (
|
||||
github.com/btcsuite/btcd v0.21.0-beta
|
||||
github.com/btcsuite/btcutil v1.0.2
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/muun/libwallet v0.8.0
|
||||
)
|
||||
|
||||
|
|
156
go.sum
|
@ -1,25 +1,39 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.33.1 h1:fmJQWZ1w9PGkHR1YL/P7HloDvqlmKQ4Vpb7PC2e+aCk=
|
||||
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e h1:F2x1bq7RaNCIuqYpswggh1+c1JmwdnkHNC9wy1KDip0=
|
||||
git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e h1:n+DcnTNkQnHlwpsrHoQtkrJIO7CBx029fw6oR4vIob4=
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
|
||||
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 h1:MG93+PZYs9PyEsj/n5/haQu2gK0h4tUtSy9ejtMwWa0=
|
||||
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2 h1:2be4ykKKov3M1yISM2E8gnGXZ/N2SsPawfnGiXxaYEU=
|
||||
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46/go.mod h1:Yktc19YNjh/Iz2//CX0vfRTS4IJKM/RKO5YZ9Fn+Pgo=
|
||||
|
@ -27,7 +41,6 @@ github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796Zt
|
|||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||
|
@ -46,12 +59,12 @@ github.com/btcsuite/btcwallet/walletdb v1.3.1/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji
|
|||
github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ=
|
||||
github.com/btcsuite/btcwallet/walletdb v1.3.3 h1:u6e7vRIKBF++cJy+hOHaMGg+88ZTwvpaY27AFvtB668=
|
||||
github.com/btcsuite/btcwallet/walletdb v1.3.3/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
|
||||
github.com/btcsuite/btcwallet/wtxmgr v1.0.0 h1:aIHgViEmZmZfe0tQQqF1xyd2qBqFWxX5vZXkkbjtbeA=
|
||||
github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY=
|
||||
github.com/btcsuite/btcwallet/wtxmgr v1.2.0 h1:ZUYPsSv8GjF9KK7lboB2OVHF0uYEcHxgrCfFWqPd9NA=
|
||||
github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 h1:nOsAWScwueMVk/VLm/dvQQD7DuanyvAUb6B3P3eT274=
|
||||
github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4=
|
||||
|
@ -63,8 +76,11 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3
|
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
||||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
|
@ -77,36 +93,52 @@ github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0
|
|||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/fiatjaf/go-lnurl v1.3.1 h1:9Qn4n1ZyzTMW/YuVX2Wr9cE+LEAzpE1hrCbxVK/yBKE=
|
||||
github.com/fiatjaf/go-lnurl v1.3.1/go.mod h1:BqA8WXAOzntF7Z3EkVO7DfP4y5rhWUmJ/Bu9KBke+rs=
|
||||
github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY=
|
||||
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM=
|
||||
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
|
@ -123,9 +155,15 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.6 h1:XvND7+MPP7Jp+JpqSZ7naSl5nVZf6k0LbL1V3EKh0zc=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk=
|
||||
github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 h1:1yY/RQWNSBjJe2GDCIYoLmpWVidrooriUr4QS/zaATQ=
|
||||
|
@ -134,8 +172,11 @@ github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 h1:o1wMw7uTNyA58IlEd
|
|||
github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7/go.mod h1:WkUxfS2JUu3qPo6tRld7ISb8HiC0gVSU91kooBMDVok=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad h1:heFfj7z0pGsNCekUlsFhO2jstxO4b5iQ665LjwM5mDc=
|
||||
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
|
||||
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
|
@ -153,22 +194,34 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
|||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c h1:3UvYABOQRhJAApj9MdCN+Ydv841ETSoy6xLzdmmr/9A=
|
||||
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
|
||||
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d h1:hJXjZMxj0SWlMoQkzeZDLi2cmeiWKa7y1B8Rg+qaoEc=
|
||||
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
|
||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
github.com/juju/retry v0.0.0-20180821225755-9058e192b216 h1:/eQL7EJQKFHByJe3DeE8Z36yqManj9UY5zppDoQi4FU=
|
||||
github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
|
||||
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2 h1:Pp8RxiF4rSoXP9SED26WCfNB28/dwTDpPXS8XMJR8rc=
|
||||
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
|
||||
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d h1:irPlN9z5VCe6BTsqVsxheCZH99OFSmqSVyTigW4mEoY=
|
||||
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
|
||||
github.com/juju/version v0.0.0-20180108022336-b64dbd566305 h1:lQxPJ1URr2fjsKnJRt/BxiIxjLt9IKGvS+0injMHbag=
|
||||
github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
|
||||
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFFoO5dR748Is8dBL9qpaTNfphQrs=
|
||||
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
|
@ -177,15 +230,16 @@ github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
|||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
|
||||
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
|
||||
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d h1:QWD/5MPnaZfUVP7P8wLa4M8Td2DI7XXHXt2vhVtUgGI=
|
||||
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
|
||||
github.com/lightningnetwork/lightning-onion v1.0.1 h1:qChGgS5+aPxFeR6JiUsGvanei1bn6WJpYbvosw/1604=
|
||||
github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
|
||||
github.com/lightningnetwork/lnd v0.10.4-beta h1:Af2zOCPePeaU8Tkl8IqtTjr4BP3zYfi+hAtQYcCMM58=
|
||||
github.com/lightningnetwork/lnd v0.10.4-beta/go.mod h1:4d02pduRVtZwgTJ+EimKJTsEAY0jDwi0SPE9h5aRneM=
|
||||
github.com/lightningnetwork/lnd/cert v1.0.2 h1:g2rEu+sM2Uyz0bpfuvwri/ks6R/26H5iY1NcGbpDJ+c=
|
||||
github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo=
|
||||
github.com/lightningnetwork/lnd/clock v1.0.1 h1:QQod8+m3KgqHdvVMV+2DRNNZS1GRFir8mHZYA+Z2hFo=
|
||||
github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
|
||||
github.com/lightningnetwork/lnd/queue v1.0.1 h1:jzJKcTy3Nj5lQrooJ3aaw9Lau3I0IwvQR5sqtjdv2R0=
|
||||
github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms=
|
||||
github.com/lightningnetwork/lnd/queue v1.0.4 h1:8Dq3vxAFSACPy+pKN88oPFhuCpCoAAChPBwa4BJxH4k=
|
||||
github.com/lightningnetwork/lnd/queue v1.0.4/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg=
|
||||
|
@ -195,22 +249,27 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG
|
|||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6 h1:b/Op1jKdoE6tzGyjzFx8gc7ZyW3hVFs1jUCQfM/Z2Jo=
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 h1:PRMAcldsl4mXKJeRNB/KVNz6TlbS6hk2Rs42PqgU3Ws=
|
||||
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/muun/libwallet v0.8.0 h1:TtMsKr5O8OWUW5khZHpptokkKuPkXhOThLZ/ck4jXPM=
|
||||
github.com/muun/libwallet v0.8.0/go.mod h1:fzmqBImU+ktQ5YDCM1MwXBl6vARC+73/ILGJMU/u96w=
|
||||
github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257 h1:NW17wq2gZlEFeW3/Zx3wSmqlD0wKGf7YvhpP+CNCsbE=
|
||||
github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257/go.mod h1:awTrhbCWjWNH4yVwZ4IE7nZbvpQ27e7OyD+jao7wRxA=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
|
@ -220,38 +279,61 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pdfcpu/pdfcpu v0.3.9 h1:gHPreswsOGwe1zViJxufbvNZf0xhK4mxj/r1CwLp958=
|
||||
github.com/pdfcpu/pdfcpu v0.3.9/go.mod h1:EfJ1EIo3n5+YlGF53DGe1yF1wQLiqK1eqGDN5LuKALs=
|
||||
github.com/pdfcpu/pdfcpu v0.3.11 h1:T5XLD5blrB61tBjkSrQnwikrQO4gmwQm61fsyGZa04w=
|
||||
github.com/pdfcpu/pdfcpu v0.3.11/go.mod h1:SZ51teSs9l709Xim2VEuOYGf+uf7RdH2eY0LrXvz7n8=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
|
||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAVZute09ocAGa7KqOON60++Gz4E=
|
||||
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY=
|
||||
github.com/urfave/cli v1.18.0 h1:m9MfmZWX7bwr9kUcs/Asr95j0IVXzGNNc+/5ku2m26Q=
|
||||
github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 h1:ASw9n1EHMftwnP3Az4XW6e308+gNsrHzmdhd0Olz9Hs=
|
||||
go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -259,20 +341,38 @@ golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU=
|
||||
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd h1:ePuNC7PZ6O5BzgPn9bZayERXBdfZjUYoXEf5BTfDfh8=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -284,20 +384,23 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -306,37 +409,55 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 h1:ZBu6861dZq7xBnG1bn5SRU0vA8nx42at4+kP07FMTog=
|
||||
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69 h1:yBHHx+XZqXJBm6Exke3N7V9gnlsyXxoCPEb1yVenjfk=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
@ -348,27 +469,36 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
|
||||
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI=
|
||||
gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
|
||||
gopkg.in/macaroon.v2 v2.0.0 h1:LVWycAfeJBUjCIqfR9gqlo7I8vmiXRr51YEOZ1suop8=
|
||||
gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
16
main.go
|
@ -9,7 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/gookit/color"
|
||||
"github.com/muun/libwallet"
|
||||
"github.com/muun/libwallet/emergencykit"
|
||||
"github.com/muun/recovery/scanner"
|
||||
|
@ -416,21 +416,19 @@ func sayBlock(message string, v ...interface{}) {
|
|||
}
|
||||
|
||||
func applyColor(colorName string, text string) string {
|
||||
boldText := aurora.Bold(text) // in most terminals, bold colors are prettier and highlight better
|
||||
|
||||
switch colorName {
|
||||
case "red":
|
||||
return aurora.Red(boldText).String()
|
||||
return color.New(color.FgRed, color.BgDefault, color.OpBold).Sprint(text)
|
||||
case "blue":
|
||||
return aurora.Blue(boldText).String()
|
||||
return color.New(color.FgBlue, color.BgDefault, color.OpBold).Sprint(text)
|
||||
case "yellow":
|
||||
return aurora.Yellow(boldText).String()
|
||||
return color.New(color.FgYellow, color.BgDefault, color.OpBold).Sprint(text)
|
||||
case "green":
|
||||
return aurora.Green(boldText).String()
|
||||
return color.New(color.FgGreen, color.BgDefault, color.OpBold).Sprint(text)
|
||||
case "white":
|
||||
return aurora.White(boldText).String()
|
||||
return color.New(color.FgWhite, color.BgDefault, color.OpBold).Sprint(text)
|
||||
case "whiteUnderline":
|
||||
return aurora.Underline(boldText).White().String()
|
||||
return color.New(color.FgWhite, color.BgDefault, color.OpBold, color.OpUnderscore).Sprint(text)
|
||||
}
|
||||
|
||||
panic("No such color: " + colorName)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
*.log
|
||||
*.swp
|
||||
.idea
|
||||
*.patch
|
||||
### Go template
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
.DS_Store
|
||||
app
|
||||
demo
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 inhere
|
||||
|
||||
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,468 @@
|
|||
# CLI Color
|
||||
|
||||
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
|
||||
[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
|
||||
[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
|
||||
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
|
||||
[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/gookit/color/badge.svg?branch=master)](https://coveralls.io/github/gookit/color?branch=master)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/color)](https://goreportcard.com/report/github.com/gookit/color)
|
||||
|
||||
A command-line color library with true color support, universal API methods and Windows support.
|
||||
|
||||
> **[中文说明](README.zh-CN.md)**
|
||||
|
||||
Basic color preview:
|
||||
|
||||
![basic-color](_examples/images/basic-color2.png)
|
||||
|
||||
Now, 256 colors and RGB colors have also been supported to work in Windows CMD and PowerShell:
|
||||
|
||||
![color-on-cmd-pwsh](_examples/images/color-on-cmd-pwsh.jpg)
|
||||
|
||||
## Features
|
||||
|
||||
- Simple to use, zero dependencies
|
||||
- Supports rich color output: 16-color (4-bit), 256-color (8-bit), true color (24-bit, RGB)
|
||||
- 16-color output is the most commonly used and most widely supported, working on any Windows version
|
||||
- Since `v1.2.4` **the 256-color (8-bit), true color (24-bit) support windows CMD and PowerShell**
|
||||
- See [this gist](https://gist.github.com/XVilka/8346728) for information on true color support
|
||||
- Generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
|
||||
- Supports HTML tag-style color rendering, such as `<green>message</>`.
|
||||
- In addition to using built-in tags, it also supports custom color attributes
|
||||
- Custom color attributes support the use of 16 color names, 256 color values, rgb color values and hex color values
|
||||
- Support working on Windows `cmd` and `powerShell` terminal
|
||||
- Basic colors: `Bold`, `Black`, `White`, `Gray`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`
|
||||
- Additional styles: `Info`, `Note`, `Light`, `Error`, `Danger`, `Notice`, `Success`, `Comment`, `Primary`, `Warning`, `Question`, `Secondary`
|
||||
- Support by set `NO_COLOR` for disable color or use `FORCE_COLOR` for force open color render.
|
||||
- Support Rgb, 256, 16 color conversion
|
||||
|
||||
## GoDoc
|
||||
|
||||
- [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
|
||||
- [godoc for github](https://pkg.go.dev/github.com/gookit/color)
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/gookit/color
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// quick use package func
|
||||
color.Redp("Simple to use color")
|
||||
color.Redln("Simple to use color")
|
||||
color.Greenp("Simple to use color\n")
|
||||
color.Cyanln("Simple to use color")
|
||||
color.Yellowln("Simple to use color")
|
||||
|
||||
// quick use like fmt.Print*
|
||||
color.Red.Println("Simple to use color")
|
||||
color.Green.Print("Simple to use color\n")
|
||||
color.Cyan.Printf("Simple to use %s\n", "color")
|
||||
color.Yellow.Printf("Simple to use %s\n", "color")
|
||||
|
||||
// use like func
|
||||
red := color.FgRed.Render
|
||||
green := color.FgGreen.Render
|
||||
fmt.Printf("%s line %s library\n", red("Command"), green("color"))
|
||||
|
||||
// custom color
|
||||
color.New(color.FgWhite, color.BgBlack).Println("custom color style")
|
||||
|
||||
// can also:
|
||||
color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
|
||||
|
||||
// internal theme/style:
|
||||
color.Info.Tips("message")
|
||||
color.Info.Prompt("message")
|
||||
color.Info.Println("message")
|
||||
color.Warn.Println("message")
|
||||
color.Error.Println("message")
|
||||
|
||||
// use style tag
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>\n")
|
||||
// Custom label attr: Supports the use of 16 color names, 256 color values, rgb color values and hex color values
|
||||
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
|
||||
|
||||
// apply a style tag
|
||||
color.Tag("info").Println("info style text")
|
||||
|
||||
// prompt message
|
||||
color.Info.Prompt("prompt style message")
|
||||
color.Warn.Prompt("prompt style message")
|
||||
|
||||
// tips message
|
||||
color.Info.Tips("tips style message")
|
||||
color.Warn.Tips("tips style message")
|
||||
}
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/demo.go`
|
||||
|
||||
![colored-out](_examples/images/color-demo.jpg)
|
||||
|
||||
## Basic/16 color
|
||||
|
||||
Supported on any Windows version. Provide generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
|
||||
|
||||
```go
|
||||
color.Bold.Println("bold message")
|
||||
color.Black.Println("bold message")
|
||||
color.White.Println("bold message")
|
||||
color.Gray.Println("bold message")
|
||||
color.Red.Println("yellow message")
|
||||
color.Blue.Println("yellow message")
|
||||
color.Cyan.Println("yellow message")
|
||||
color.Yellow.Println("yellow message")
|
||||
color.Magenta.Println("yellow message")
|
||||
|
||||
// Only use foreground color
|
||||
color.FgCyan.Printf("Simple to use %s\n", "color")
|
||||
// Only use background color
|
||||
color.BgRed.Printf("Simple to use %s\n", "color")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/color_16.go`
|
||||
|
||||
![basic-color](_examples/images/basic-color.png)
|
||||
|
||||
### Custom build color
|
||||
|
||||
```go
|
||||
// Full custom: foreground, background, option
|
||||
myStyle := color.New(color.FgWhite, color.BgBlack, color.OpBold)
|
||||
myStyle.Println("custom color style")
|
||||
|
||||
// can also:
|
||||
color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
|
||||
```
|
||||
|
||||
custom set console settings:
|
||||
|
||||
```go
|
||||
// set console color
|
||||
color.Set(color.FgCyan)
|
||||
|
||||
// print message
|
||||
fmt.Print("message")
|
||||
|
||||
// reset console settings
|
||||
color.Reset()
|
||||
```
|
||||
|
||||
### Additional styles
|
||||
|
||||
provide generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
|
||||
|
||||
print message use defined style:
|
||||
|
||||
```go
|
||||
color.Info.Println("Info message")
|
||||
color.Note.Println("Note message")
|
||||
color.Notice.Println("Notice message")
|
||||
color.Error.Println("Error message")
|
||||
color.Danger.Println("Danger message")
|
||||
color.Warn.Println("Warn message")
|
||||
color.Debug.Println("Debug message")
|
||||
color.Primary.Println("Primary message")
|
||||
color.Question.Println("Question message")
|
||||
color.Secondary.Println("Secondary message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_basic.go`
|
||||
|
||||
![theme-basic](_examples/images/theme-basic.png)
|
||||
|
||||
**Tips style**
|
||||
|
||||
```go
|
||||
color.Info.Tips("Info tips message")
|
||||
color.Note.Tips("Note tips message")
|
||||
color.Notice.Tips("Notice tips message")
|
||||
color.Error.Tips("Error tips message")
|
||||
color.Danger.Tips("Danger tips message")
|
||||
color.Warn.Tips("Warn tips message")
|
||||
color.Debug.Tips("Debug tips message")
|
||||
color.Primary.Tips("Primary tips message")
|
||||
color.Question.Tips("Question tips message")
|
||||
color.Secondary.Tips("Secondary tips message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_tips.go`
|
||||
|
||||
![theme-tips](_examples/images/theme-tips.png)
|
||||
|
||||
**Prompt Style**
|
||||
|
||||
```go
|
||||
color.Info.Prompt("Info prompt message")
|
||||
color.Note.Prompt("Note prompt message")
|
||||
color.Notice.Prompt("Notice prompt message")
|
||||
color.Error.Prompt("Error prompt message")
|
||||
color.Danger.Prompt("Danger prompt message")
|
||||
color.Warn.Prompt("Warn prompt message")
|
||||
color.Debug.Prompt("Debug prompt message")
|
||||
color.Primary.Prompt("Primary prompt message")
|
||||
color.Question.Prompt("Question prompt message")
|
||||
color.Secondary.Prompt("Secondary prompt message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_prompt.go`
|
||||
|
||||
![theme-prompt](_examples/images/theme-prompt.png)
|
||||
|
||||
**Block Style**
|
||||
|
||||
```go
|
||||
color.Info.Block("Info block message")
|
||||
color.Note.Block("Note block message")
|
||||
color.Notice.Block("Notice block message")
|
||||
color.Error.Block("Error block message")
|
||||
color.Danger.Block("Danger block message")
|
||||
color.Warn.Block("Warn block message")
|
||||
color.Debug.Block("Debug block message")
|
||||
color.Primary.Block("Primary block message")
|
||||
color.Question.Block("Question block message")
|
||||
color.Secondary.Block("Secondary block message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_block.go`
|
||||
|
||||
![theme-block](_examples/images/theme-block.png)
|
||||
|
||||
## 256-color usage
|
||||
|
||||
> 256 colors support Windows CMD, PowerShell environment after `v1.2.4`
|
||||
|
||||
### Set the foreground or background color
|
||||
|
||||
- `color.C256(val uint8, isBg ...bool) Color256`
|
||||
|
||||
```go
|
||||
c := color.C256(132) // fg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c := color.C256(132, true) // bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
### 256-color style
|
||||
|
||||
Can be used to set foreground and background colors at the same time.
|
||||
|
||||
- `S256(fgAndBg ...uint8) *Style256`
|
||||
|
||||
```go
|
||||
s := color.S256(32, 203)
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
with options:
|
||||
|
||||
```go
|
||||
s := color.S256(32, 203)
|
||||
s.SetOpts(color.Opts{color.OpBold})
|
||||
|
||||
s.Println("style with options")
|
||||
s.Printf("style with %s\n", "options")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/color_256.go`
|
||||
|
||||
![color-tags](_examples/images/color-256.png)
|
||||
|
||||
## RGB/True color
|
||||
|
||||
> RGB colors support Windows `CMD`, `PowerShell` environment after `v1.2.4`
|
||||
|
||||
**Preview:**
|
||||
|
||||
> Run demo: `Run demo: go run ./_examples/color_rgb.go`
|
||||
|
||||
![color-rgb](_examples/images/color-rgb.png)
|
||||
|
||||
example:
|
||||
|
||||
```go
|
||||
color.RGB(30, 144, 255).Println("message. use RGB number")
|
||||
|
||||
color.HEX("#1976D2").Println("blue-darken")
|
||||
color.HEX("#D50000", true).Println("red-accent. use HEX style")
|
||||
|
||||
color.RGBStyleFromString("213,0,0").Println("red-accent. use RGB number")
|
||||
color.HEXStyle("eee", "D50000").Println("deep-purple color")
|
||||
```
|
||||
|
||||
### Set the foreground or background color
|
||||
|
||||
- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor`
|
||||
|
||||
```go
|
||||
c := color.RGB(30,144,255) // fg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c := color.RGB(30,144,255, true) // bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
Create a style from an hexadecimal color string:
|
||||
|
||||
- `color.HEX(hex string, isBg ...bool) RGBColor`
|
||||
|
||||
```go
|
||||
c := color.HEX("ccc") // can also: "cccccc" "#cccccc"
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c = color.HEX("aabbcc", true) // as bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
### RGB color style
|
||||
|
||||
Can be used to set the foreground and background colors at the same time.
|
||||
|
||||
- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle`
|
||||
|
||||
```go
|
||||
s := color.NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23))
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
Create a style from an hexadecimal color string:
|
||||
|
||||
- `color.HEXStyle(fg string, bg ...string) *RGBStyle`
|
||||
|
||||
```go
|
||||
s := color.HEXStyle("11aa23", "eee")
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
with options:
|
||||
|
||||
```go
|
||||
s := color.HEXStyle("11aa23", "eee")
|
||||
s.SetOpts(color.Opts{color.OpBold})
|
||||
|
||||
s.Println("style with options")
|
||||
s.Printf("style with %s\n", "options")
|
||||
```
|
||||
|
||||
## HTML-like tag usage
|
||||
|
||||
**Supported** on Windows `cmd.exe` `PowerShell` .
|
||||
|
||||
```go
|
||||
// use style tag
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
|
||||
color.Println("<suc>hello</>")
|
||||
color.Println("<error>hello</>")
|
||||
color.Println("<warning>hello</>")
|
||||
|
||||
// custom color attributes
|
||||
color.Print("<fg=yellow;bg=black;op=underscore;>hello, welcome</>\n")
|
||||
|
||||
// Custom label attr: Supports the use of 16 color names, 256 color values, rgb color values and hex color values
|
||||
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
|
||||
```
|
||||
|
||||
- `color.Tag`
|
||||
|
||||
```go
|
||||
// set a style tag
|
||||
color.Tag("info").Print("info style text")
|
||||
color.Tag("info").Printf("%s style text", "info")
|
||||
color.Tag("info").Println("info style text")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/color_tag.go`
|
||||
|
||||
![color-tags](_examples/images/color-tags.png)
|
||||
|
||||
## Color convert
|
||||
|
||||
Supports conversion between Rgb, 256, 16 colors, `Rgb <=> 256 <=> 16`
|
||||
|
||||
```go
|
||||
basic := color.Red
|
||||
basic.Println("basic color")
|
||||
|
||||
c256 := color.Red.C256()
|
||||
c256.Println("256 color")
|
||||
c256.C16().Println("basic color")
|
||||
|
||||
rgb := color.Red.RGB()
|
||||
rgb.Println("rgb color")
|
||||
rgb.C256().Println("256 color")
|
||||
```
|
||||
|
||||
## Func refer
|
||||
|
||||
There are some useful functions reference
|
||||
|
||||
- `Disable()` disable color render
|
||||
- `SetOutput(io.Writer)` custom set the colored text output writer
|
||||
- `ForceOpenColor()` force open color render
|
||||
- `Colors2code(colors ...Color) string` Convert colors to code. return like "32;45;3"
|
||||
- `ClearCode(str string) string` Use for clear color codes
|
||||
- `ClearTag(s string) string` clear all color html-tag for a string
|
||||
- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
|
||||
- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
|
||||
- `RgbToHex(rgb []int) string` Convert RGB to hex code
|
||||
- More useful func please see https://pkg.go.dev/github.com/gookit/color
|
||||
|
||||
## Project use
|
||||
|
||||
Check out these projects, which use https://github.com/gookit/color :
|
||||
|
||||
- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
|
||||
|
||||
## Gookit packages
|
||||
|
||||
- [gookit/ini](https://github.com/gookit/ini) Go config management, use INI files
|
||||
- [gookit/rux](https://github.com/gookit/rux) Simple and fast request router for golang HTTP
|
||||
- [gookit/gcli](https://github.com/gookit/gcli) build CLI application, tool library, running CLI commands
|
||||
- [gookit/slog](https://github.com/gookit/slog) Concise and extensible go log library
|
||||
- [gookit/event](https://github.com/gookit/event) Lightweight event manager and dispatcher implements by Go
|
||||
- [gookit/cache](https://github.com/gookit/cache) Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
|
||||
- [gookit/config](https://github.com/gookit/config) Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
|
||||
- [gookit/color](https://github.com/gookit/color) A command-line color library with true color support, universal API methods and Windows support
|
||||
- [gookit/filter](https://github.com/gookit/filter) Provide filtering, sanitizing, and conversion of golang data
|
||||
- [gookit/validate](https://github.com/gookit/validate) Use for data validation and filtering. support Map, Struct, Form data
|
||||
- [gookit/goutil](https://github.com/gookit/goutil) Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
|
||||
- More, please see https://github.com/gookit
|
||||
|
||||
## See also
|
||||
|
||||
- [inhere/console](https://github.com/inhere/php-console)
|
||||
- [xo/terminfo](https://github.com/xo/terminfo)
|
||||
- [beego/bee](https://github.com/beego/bee)
|
||||
- [issue9/term](https://github.com/issue9/term)
|
||||
- [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code)
|
||||
- [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
|
||||
- [Terminal Colors](https://gist.github.com/XVilka/8346728)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](/LICENSE)
|
|
@ -0,0 +1,472 @@
|
|||
# CLI Color
|
||||
|
||||
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
|
||||
[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
|
||||
[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
|
||||
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
|
||||
[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/gookit/color/badge.svg?branch=master)](https://coveralls.io/github/gookit/color?branch=master)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/color)](https://goreportcard.com/report/github.com/gookit/color)
|
||||
|
||||
Golang下的命令行色彩使用库, 拥有丰富的色彩渲染输出,通用的API方法,兼容Windows系统
|
||||
|
||||
> **[EN README](README.md)**
|
||||
|
||||
基本颜色预览:
|
||||
|
||||
![basic-color](_examples/images/basic-color2.png)
|
||||
|
||||
现在,256色和RGB色彩也已经支持windows CMD和PowerShell中工作:
|
||||
|
||||
![color-on-cmd-pwsh](_examples/images/color-on-cmd-pwsh.jpg)
|
||||
|
||||
## 功能特色
|
||||
|
||||
- 使用简单方便
|
||||
- 支持丰富的颜色输出, 16色(4bit),256色(8bit),RGB色彩(24bit, RGB)
|
||||
- 16色(4bit)是最常用和支持最广的,支持Windows `cmd.exe`
|
||||
- 自 `v1.2.4` 起 **256色(8bit),RGB色彩(24bit)均支持Windows CMD和PowerShell终端**
|
||||
- 请查看 [this gist](https://gist.github.com/XVilka/8346728) 了解支持RGB色彩的终端
|
||||
- 提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
|
||||
- 同时支持html标签式的颜色渲染,除了使用内置标签,同时支持自定义颜色属性
|
||||
- 例如: `this an <green>message</>` 标签内部的文本将会渲染为绿色字体
|
||||
- 自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
|
||||
- 基础色彩: `Bold` `Black` `White` `Gray` `Red` `Green` `Yellow` `Blue` `Magenta` `Cyan`
|
||||
- 扩展风格: `Info` `Note` `Light` `Error` `Danger` `Notice` `Success` `Comment` `Primary` `Warning` `Question` `Secondary`
|
||||
- 支持通过设置环境变量 `NO_COLOR` 来禁用色彩,或者使用 `FORCE_COLOR` 来强制使用色彩渲染.
|
||||
- 支持 Rgb, 256, 16 色彩之间的互相转换
|
||||
- 支持Linux、Mac,同时兼容Windows系统环境
|
||||
|
||||
## GoDoc
|
||||
|
||||
- [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
|
||||
- [godoc for github](https://pkg.go.dev/github.com/gookit/color)
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
go get github.com/gookit/color
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
如下,引入当前包就可以快速的使用
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 简单快速的使用,跟 fmt.Print* 类似
|
||||
color.Redp("Simple to use color")
|
||||
color.Redln("Simple to use color")
|
||||
color.Greenp("Simple to use color\n")
|
||||
color.Cyanln("Simple to use color")
|
||||
color.Yellowln("Simple to use color")
|
||||
|
||||
// 简单快速的使用,跟 fmt.Print* 类似
|
||||
color.Red.Println("Simple to use color")
|
||||
color.Green.Print("Simple to use color\n")
|
||||
color.Cyan.Printf("Simple to use %s\n", "color")
|
||||
color.Yellow.Printf("Simple to use %s\n", "color")
|
||||
|
||||
// use like func
|
||||
red := color.FgRed.Render
|
||||
green := color.FgGreen.Render
|
||||
fmt.Printf("%s line %s library\n", red("Command"), green("color"))
|
||||
|
||||
// 自定义颜色
|
||||
color.New(color.FgWhite, color.BgBlack).Println("custom color style")
|
||||
|
||||
// 也可以:
|
||||
color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
|
||||
|
||||
// internal style:
|
||||
color.Info.Println("message")
|
||||
color.Warn.Println("message")
|
||||
color.Error.Println("message")
|
||||
|
||||
// 使用内置颜色标签
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>\n")
|
||||
// 自定义标签: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
|
||||
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
|
||||
|
||||
// apply a style tag
|
||||
color.Tag("info").Println("info style text")
|
||||
|
||||
// prompt message
|
||||
color.Info.Prompt("prompt style message")
|
||||
color.Warn.Prompt("prompt style message")
|
||||
|
||||
// tips message
|
||||
color.Info.Tips("tips style message")
|
||||
color.Warn.Tips("tips style message")
|
||||
}
|
||||
```
|
||||
|
||||
> 运行 demo: `go run ./_examples/demo.go`
|
||||
|
||||
![colored-out](_examples/images/color-demo.jpg)
|
||||
|
||||
## 基础颜色(16-color)
|
||||
|
||||
提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
|
||||
|
||||
> 支持在windows `cmd.exe` `powerShell` 等终端使用
|
||||
|
||||
```go
|
||||
color.Bold.Println("bold message")
|
||||
color.Black.Println("bold message")
|
||||
color.White.Println("bold message")
|
||||
color.Gray.Println("bold message")
|
||||
color.Red.Println("yellow message")
|
||||
color.Blue.Println("yellow message")
|
||||
color.Cyan.Println("yellow message")
|
||||
color.Yellow.Println("yellow message")
|
||||
color.Magenta.Println("yellow message")
|
||||
|
||||
// Only use foreground color
|
||||
color.FgCyan.Printf("Simple to use %s\n", "color")
|
||||
// Only use background color
|
||||
color.BgRed.Printf("Simple to use %s\n", "color")
|
||||
```
|
||||
|
||||
> 运行demo: `go run ./_examples/color_16.go`
|
||||
|
||||
![basic-color](_examples/images/basic-color.png)
|
||||
|
||||
### 构建风格
|
||||
|
||||
```go
|
||||
// 仅设置前景色
|
||||
color.FgCyan.Printf("Simple to use %s\n", "color")
|
||||
// 仅设置背景色
|
||||
color.BgRed.Printf("Simple to use %s\n", "color")
|
||||
|
||||
// 完全自定义: 前景色 背景色 选项
|
||||
style := color.New(color.FgWhite, color.BgBlack, color.OpBold)
|
||||
style.Println("custom color style")
|
||||
|
||||
// 也可以:
|
||||
color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
|
||||
```
|
||||
|
||||
直接设置控制台属性:
|
||||
|
||||
```go
|
||||
// 设置console颜色
|
||||
color.Set(color.FgCyan)
|
||||
|
||||
// 输出信息
|
||||
fmt.Print("message")
|
||||
|
||||
// 重置console颜色
|
||||
color.Reset()
|
||||
```
|
||||
|
||||
> 当然,color已经内置丰富的色彩风格支持
|
||||
|
||||
### 扩展风格方法
|
||||
|
||||
提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
|
||||
|
||||
> 支持在windows `cmd.exe` `powerShell` 等终端使用
|
||||
|
||||
基础使用:
|
||||
|
||||
```go
|
||||
// print message
|
||||
color.Info.Println("Info message")
|
||||
color.Note.Println("Note message")
|
||||
color.Notice.Println("Notice message")
|
||||
color.Error.Println("Error message")
|
||||
color.Danger.Println("Danger message")
|
||||
color.Warn.Println("Warn message")
|
||||
color.Debug.Println("Debug message")
|
||||
color.Primary.Println("Primary message")
|
||||
color.Question.Println("Question message")
|
||||
color.Secondary.Println("Secondary message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_basic.go`
|
||||
|
||||
![theme-basic](_examples/images/theme-basic.png)
|
||||
|
||||
**简约提示风格**
|
||||
|
||||
```go
|
||||
color.Info.Tips("Info tips message")
|
||||
color.Note.Tips("Note tips message")
|
||||
color.Notice.Tips("Notice tips message")
|
||||
color.Error.Tips("Error tips message")
|
||||
color.Danger.Tips("Danger tips message")
|
||||
color.Warn.Tips("Warn tips message")
|
||||
color.Debug.Tips("Debug tips message")
|
||||
color.Primary.Tips("Primary tips message")
|
||||
color.Question.Tips("Question tips message")
|
||||
color.Secondary.Tips("Secondary tips message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_tips.go`
|
||||
|
||||
![theme-tips](_examples/images/theme-tips.png)
|
||||
|
||||
**着重提示风格**
|
||||
|
||||
```go
|
||||
color.Info.Prompt("Info prompt message")
|
||||
color.Note.Prompt("Note prompt message")
|
||||
color.Notice.Prompt("Notice prompt message")
|
||||
color.Error.Prompt("Error prompt message")
|
||||
color.Danger.Prompt("Danger prompt message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_prompt.go`
|
||||
|
||||
![theme-prompt](_examples/images/theme-prompt.png)
|
||||
|
||||
**强调提示风格**
|
||||
|
||||
```go
|
||||
color.Warn.Block("Warn block message")
|
||||
color.Debug.Block("Debug block message")
|
||||
color.Primary.Block("Primary block message")
|
||||
color.Question.Block("Question block message")
|
||||
color.Secondary.Block("Secondary block message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_block.go`
|
||||
|
||||
![theme-block](_examples/images/theme-block.png)
|
||||
|
||||
## 256 色彩使用
|
||||
|
||||
> 256色彩在 `v1.2.4` 后支持Windows CMD,PowerShell 环境
|
||||
|
||||
### 使用前景或后景色
|
||||
|
||||
- `color.C256(val uint8, isBg ...bool) Color256`
|
||||
|
||||
```go
|
||||
c := color.C256(132) // fg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c := color.C256(132, true) // bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
### 使用256 色彩风格
|
||||
|
||||
> 可同时设置前景和背景色
|
||||
|
||||
- `color.S256(fgAndBg ...uint8) *Style256`
|
||||
|
||||
```go
|
||||
s := color.S256(32, 203)
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
可以同时添加选项设置:
|
||||
|
||||
```go
|
||||
s := color.S256(32, 203)
|
||||
s.SetOpts(color.Opts{color.OpBold})
|
||||
|
||||
s.Println("style with options")
|
||||
s.Printf("style with %s\n", "options")
|
||||
```
|
||||
|
||||
> 运行 demo: `go run ./_examples/color_256.go`
|
||||
|
||||
![color-tags](_examples/images/color-256.png)
|
||||
|
||||
## RGB/True色彩使用
|
||||
|
||||
> RGB色彩在 `v1.2.4` 后支持 Windows `CMD`, `PowerShell` 环境
|
||||
|
||||
**效果预览:**
|
||||
|
||||
> 运行 demo: `Run demo: go run ./_examples/color_rgb.go`
|
||||
|
||||
![color-rgb](_examples/images/color-rgb.png)
|
||||
|
||||
代码示例:
|
||||
|
||||
```go
|
||||
color.RGB(30, 144, 255).Println("message. use RGB number")
|
||||
|
||||
color.HEX("#1976D2").Println("blue-darken")
|
||||
color.HEX("#D50000", true).Println("red-accent. use HEX style")
|
||||
|
||||
color.RGBStyleFromString("213,0,0").Println("red-accent. use RGB number")
|
||||
color.HEXStyle("eee", "D50000").Println("deep-purple color")
|
||||
```
|
||||
|
||||
### 使用前景或后景色
|
||||
|
||||
- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor`
|
||||
|
||||
```go
|
||||
c := color.RGB(30,144,255) // fg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c := color.RGB(30,144,255, true) // bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
- `color.HEX(hex string, isBg ...bool) RGBColor` 从16进制颜色创建
|
||||
|
||||
```go
|
||||
c := color.HEX("ccc") // 也可以写为: "cccccc" "#cccccc"
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
|
||||
c = color.HEX("aabbcc", true) // as bg color
|
||||
c.Println("message")
|
||||
c.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
### 使用RGB风格
|
||||
|
||||
> 可同时设置前景和背景色
|
||||
|
||||
- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle`
|
||||
|
||||
```go
|
||||
s := color.NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23))
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
- `color.HEXStyle(fg string, bg ...string) *RGBStyle` 从16进制颜色创建
|
||||
|
||||
```go
|
||||
s := color.HEXStyle("11aa23", "eee")
|
||||
s.Println("message")
|
||||
s.Printf("format %s", "message")
|
||||
```
|
||||
|
||||
- 可以同时添加选项设置:
|
||||
|
||||
```go
|
||||
s := color.HEXStyle("11aa23", "eee")
|
||||
s.SetOpts(color.Opts{color.OpBold})
|
||||
|
||||
s.Println("style with options")
|
||||
s.Printf("style with %s\n", "options")
|
||||
```
|
||||
|
||||
## 使用颜色标签
|
||||
|
||||
> **支持** 在windows `cmd.exe` `PowerShell` 使用
|
||||
|
||||
使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式
|
||||
|
||||
> 同时支持自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
|
||||
|
||||
```go
|
||||
// 使用内置的 color tag
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
|
||||
color.Println("<suc>hello</>")
|
||||
color.Println("<error>hello</>")
|
||||
color.Println("<warning>hello</>")
|
||||
|
||||
// 自定义颜色属性
|
||||
color.Print("<fg=yellow;bg=black;op=underscore;>hello, welcome</>\n")
|
||||
|
||||
// 自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
|
||||
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
|
||||
```
|
||||
|
||||
- 使用 `color.Tag`
|
||||
|
||||
给后面输出的文本信息加上给定的颜色风格标签
|
||||
|
||||
```go
|
||||
// set a style tag
|
||||
color.Tag("info").Print("info style text")
|
||||
color.Tag("info").Printf("%s style text", "info")
|
||||
color.Tag("info").Println("info style text")
|
||||
```
|
||||
|
||||
> 运行 demo: `go run ./_examples/color_tag.go`
|
||||
|
||||
![color-tags](_examples/images/color-tags.png)
|
||||
|
||||
## 颜色转换
|
||||
|
||||
支持 Rgb, 256, 16 色彩之间的互相转换 `Rgb <=> 256 <=> 16`
|
||||
|
||||
```go
|
||||
basic := color.Red
|
||||
basic.Println("basic color")
|
||||
|
||||
c256 := color.Red.C256()
|
||||
c256.Println("256 color")
|
||||
c256.C16().Println("basic color")
|
||||
|
||||
rgb := color.Red.RGB()
|
||||
rgb.Println("rgb color")
|
||||
rgb.C256().Println("256 color")
|
||||
```
|
||||
|
||||
## 方法参考
|
||||
|
||||
一些有用的工具方法参考
|
||||
|
||||
- `Disable()` disable color render
|
||||
- `SetOutput(io.Writer)` custom set the colored text output writer
|
||||
- `ForceOpenColor()` force open color render
|
||||
- `ClearCode(str string) string` Use for clear color codes
|
||||
- `Colors2code(colors ...Color) string` Convert colors to code. return like "32;45;3"
|
||||
- `ClearTag(s string) string` clear all color html-tag for a string
|
||||
- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
|
||||
- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
|
||||
- `RgbToHex(rgb []int) string` Convert RGB to hex code
|
||||
- 更多请查看文档 https://pkg.go.dev/github.com/gookit/color
|
||||
|
||||
## 使用color的项目
|
||||
|
||||
看看这些使用了 https://github.com/gookit/color 的项目:
|
||||
|
||||
- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
|
||||
|
||||
## Gookit 工具包
|
||||
|
||||
- [gookit/ini](https://github.com/gookit/ini) INI配置读取管理,支持多文件加载,数据覆盖合并, 解析ENV变量, 解析变量引用
|
||||
- [gookit/rux](https://github.com/gookit/rux) Simple and fast request router for golang HTTP
|
||||
- [gookit/gcli](https://github.com/gookit/gcli) Go的命令行应用,工具库,运行CLI命令,支持命令行色彩,用户交互,进度显示,数据格式化显示
|
||||
- [gookit/slog](https://github.com/gookit/slog) 简洁易扩展的go日志库
|
||||
- [gookit/event](https://github.com/gookit/event) Go实现的轻量级的事件管理、调度程序库, 支持设置监听器的优先级, 支持对一组事件进行监听
|
||||
- [gookit/cache](https://github.com/gookit/cache) 通用的缓存使用包装库,通过包装各种常用的驱动,来提供统一的使用API
|
||||
- [gookit/config](https://github.com/gookit/config) Go应用配置管理,支持多种格式(JSON, YAML, TOML, INI, HCL, ENV, Flags),多文件加载,远程文件加载,数据合并
|
||||
- [gookit/color](https://github.com/gookit/color) CLI 控制台颜色渲染工具库, 拥有简洁的使用API,支持16色,256色,RGB色彩渲染输出
|
||||
- [gookit/filter](https://github.com/gookit/filter) 提供对Golang数据的过滤,净化,转换
|
||||
- [gookit/validate](https://github.com/gookit/validate) Go通用的数据验证与过滤库,使用简单,内置大部分常用验证、过滤器
|
||||
- [gookit/goutil](https://github.com/gookit/goutil) Go 的一些工具函数,格式化,特殊处理,常用信息获取等
|
||||
- 更多请查看 https://github.com/gookit
|
||||
|
||||
## 参考项目
|
||||
|
||||
- [inhere/console](https://github.com/inhere/php-console)
|
||||
- [xo/terminfo](https://github.com/xo/terminfo)
|
||||
- [beego/bee](https://github.com/beego/bee)
|
||||
- [issue9/term](https://github.com/issue9/term)
|
||||
- [ANSI转义序列](https://zh.wikipedia.org/wiki/ANSI转义序列)
|
||||
- [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
|
||||
- [Terminal Colors](https://gist.github.com/XVilka/8346728)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
Package color is Command line color library.
|
||||
Support rich color rendering output, universal API method, compatible with Windows system
|
||||
|
||||
Source code and other details for the project are available at GitHub:
|
||||
|
||||
https://github.com/gookit/color
|
||||
|
||||
More usage please see README and tests.
|
||||
*/
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
// terminal color available level alias of the terminfo.ColorLevel*
|
||||
const (
|
||||
LevelNo = terminfo.ColorLevelNone // not support color.
|
||||
Level16 = terminfo.ColorLevelBasic // 3/4 bit color supported
|
||||
Level256 = terminfo.ColorLevelHundreds // 8 bit color supported
|
||||
LevelRgb = terminfo.ColorLevelMillions // (24 bit)true color supported
|
||||
)
|
||||
|
||||
// color render templates
|
||||
// ESC 操作的表示:
|
||||
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
|
||||
const (
|
||||
SettingTpl = "\x1b[%sm"
|
||||
FullColorTpl = "\x1b[%sm%s\x1b[0m"
|
||||
)
|
||||
|
||||
// ResetSet Close all properties.
|
||||
const ResetSet = "\x1b[0m"
|
||||
|
||||
// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
|
||||
const CodeExpr = `\033\[[\d;?]+m`
|
||||
|
||||
var (
|
||||
// Enable switch color render and display
|
||||
//
|
||||
// NOTICE:
|
||||
// if ENV: NO_COLOR is not empty, will disable color render.
|
||||
Enable = os.Getenv("NO_COLOR") == ""
|
||||
// RenderTag render HTML tag on call color.Xprint, color.PrintX
|
||||
RenderTag = true
|
||||
// debug mode for development.
|
||||
//
|
||||
// set env:
|
||||
// COLOR_DEBUG_MODE=on
|
||||
// or:
|
||||
// COLOR_DEBUG_MODE=on go run ./_examples/envcheck.go
|
||||
debugMode = os.Getenv("COLOR_DEBUG_MODE") == "on"
|
||||
// inner errors record on detect color level
|
||||
innerErrs []error
|
||||
// output the default io.Writer message print
|
||||
output io.Writer = os.Stdout
|
||||
// mark current env, It's like in `cmd.exe`
|
||||
// if not in windows, it's always is False.
|
||||
isLikeInCmd bool
|
||||
// the color support level for current terminal
|
||||
// needVTP - need enable VTP, only for windows OS
|
||||
colorLevel, needVTP = detectTermColorLevel()
|
||||
// match color codes
|
||||
codeRegex = regexp.MustCompile(CodeExpr)
|
||||
// mark current env is support color.
|
||||
// Always: isLikeInCmd != supportColor
|
||||
// supportColor = IsSupportColor()
|
||||
)
|
||||
|
||||
// TermColorLevel value on current ENV
|
||||
func TermColorLevel() terminfo.ColorLevel {
|
||||
return colorLevel
|
||||
}
|
||||
|
||||
// SupportColor on the current ENV
|
||||
func SupportColor() bool {
|
||||
return colorLevel > terminfo.ColorLevelNone
|
||||
}
|
||||
|
||||
// Support16Color on the current ENV
|
||||
// func Support16Color() bool {
|
||||
// return colorLevel > terminfo.ColorLevelNone
|
||||
// }
|
||||
|
||||
// Support256Color on the current ENV
|
||||
func Support256Color() bool {
|
||||
return colorLevel > terminfo.ColorLevelBasic
|
||||
}
|
||||
|
||||
// SupportTrueColor on the current ENV
|
||||
func SupportTrueColor() bool {
|
||||
return colorLevel > terminfo.ColorLevelHundreds
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* global settings
|
||||
*************************************************************/
|
||||
|
||||
// Set set console color attributes
|
||||
func Set(colors ...Color) (int, error) {
|
||||
code := Colors2code(colors...)
|
||||
err := SetTerminal(code)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Reset reset console color attributes
|
||||
func Reset() (int, error) {
|
||||
err := ResetTerminal()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Disable disable color output
|
||||
func Disable() bool {
|
||||
oldVal := Enable
|
||||
Enable = false
|
||||
return oldVal
|
||||
}
|
||||
|
||||
// NotRenderTag on call color.Xprint, color.PrintX
|
||||
func NotRenderTag() {
|
||||
RenderTag = false
|
||||
}
|
||||
|
||||
// SetOutput set default colored text output
|
||||
func SetOutput(w io.Writer) {
|
||||
output = w
|
||||
}
|
||||
|
||||
// ResetOutput reset output
|
||||
func ResetOutput() {
|
||||
output = os.Stdout
|
||||
}
|
||||
|
||||
// ResetOptions reset all package option setting
|
||||
func ResetOptions() {
|
||||
RenderTag = true
|
||||
Enable = true
|
||||
output = os.Stdout
|
||||
}
|
||||
|
||||
// ForceColor force open color render
|
||||
func ForceSetColorLevel(level terminfo.ColorLevel) terminfo.ColorLevel {
|
||||
oldLevelVal := colorLevel
|
||||
colorLevel = level
|
||||
return oldLevelVal
|
||||
}
|
||||
|
||||
// ForceColor force open color render
|
||||
func ForceColor() terminfo.ColorLevel {
|
||||
return ForceOpenColor()
|
||||
}
|
||||
|
||||
// ForceOpenColor force open color render
|
||||
func ForceOpenColor() terminfo.ColorLevel {
|
||||
// TODO should set level to ?
|
||||
return ForceSetColorLevel(terminfo.ColorLevelMillions)
|
||||
}
|
||||
|
||||
// IsLikeInCmd check result
|
||||
// Deprecated
|
||||
func IsLikeInCmd() bool {
|
||||
return isLikeInCmd
|
||||
}
|
||||
|
||||
// InnerErrs info
|
||||
func InnerErrs() []error {
|
||||
return innerErrs
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* render color code
|
||||
*************************************************************/
|
||||
|
||||
// RenderCode render message by color code.
|
||||
// Usage:
|
||||
// msg := RenderCode("3;32;45", "some", "message")
|
||||
func RenderCode(code string, args ...interface{}) string {
|
||||
var message string
|
||||
if ln := len(args); ln == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
message = fmt.Sprint(args...)
|
||||
if len(code) == 0 {
|
||||
return message
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !Enable || !SupportColor() {
|
||||
return ClearCode(message)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(FullColorTpl, code, message)
|
||||
}
|
||||
|
||||
// RenderWithSpaces Render code with spaces.
|
||||
// If the number of args is > 1, a space will be added between the args
|
||||
func RenderWithSpaces(code string, args ...interface{}) string {
|
||||
message := formatArgsForPrintln(args)
|
||||
if len(code) == 0 {
|
||||
return message
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !Enable || !SupportColor() {
|
||||
return ClearCode(message)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(FullColorTpl, code, message)
|
||||
}
|
||||
|
||||
// RenderString render a string with color code.
|
||||
// Usage:
|
||||
// msg := RenderString("3;32;45", "a message")
|
||||
func RenderString(code string, str string) string {
|
||||
if len(code) == 0 || str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !Enable || !SupportColor() {
|
||||
return ClearCode(str)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(FullColorTpl, code, str)
|
||||
}
|
||||
|
||||
// ClearCode clear color codes.
|
||||
// eg: "\033[36;1mText\x1b[0m" -> "Text"
|
||||
func ClearCode(str string) string {
|
||||
return codeRegex.ReplaceAllString(str, "")
|
||||
}
|
|
@ -0,0 +1,440 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Color Color16, 16 color value type
|
||||
// 3(2^3=8) OR 4(2^4=16) bite color.
|
||||
type Color uint8
|
||||
type Basic = Color // alias of Color
|
||||
|
||||
// Opts basic color options. code: 0 - 9
|
||||
type Opts []Color
|
||||
|
||||
// Add option value
|
||||
func (o *Opts) Add(ops ...Color) {
|
||||
for _, op := range ops {
|
||||
if uint8(op) < 10 {
|
||||
*o = append(*o, op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid options
|
||||
func (o Opts) IsValid() bool {
|
||||
return len(o) > 0
|
||||
}
|
||||
|
||||
// IsEmpty options
|
||||
func (o Opts) IsEmpty() bool {
|
||||
return len(o) == 0
|
||||
}
|
||||
|
||||
// String options to string. eg: "1;3"
|
||||
func (o Opts) String() string {
|
||||
return Colors2code(o...)
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Basic 16 color definition
|
||||
*************************************************************/
|
||||
|
||||
// Base value for foreground/background color
|
||||
const (
|
||||
FgBase uint8 = 30
|
||||
BgBase uint8 = 40
|
||||
// hi color base code
|
||||
HiFgBase uint8 = 90
|
||||
HiBgBase uint8 = 100
|
||||
)
|
||||
|
||||
// Foreground colors. basic foreground colors 30 - 37
|
||||
const (
|
||||
FgBlack Color = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta // 品红
|
||||
FgCyan // 青色
|
||||
FgWhite
|
||||
// FgDefault revert default FG
|
||||
FgDefault Color = 39
|
||||
)
|
||||
|
||||
// Extra foreground color 90 - 97(非标准)
|
||||
const (
|
||||
FgDarkGray Color = iota + 90 // 亮黑(灰)
|
||||
FgLightRed
|
||||
FgLightGreen
|
||||
FgLightYellow
|
||||
FgLightBlue
|
||||
FgLightMagenta
|
||||
FgLightCyan
|
||||
FgLightWhite
|
||||
// FgGray is alias of FgDarkGray
|
||||
FgGray Color = 90 // 亮黑(灰)
|
||||
)
|
||||
|
||||
// Background colors. basic background colors 40 - 47
|
||||
const (
|
||||
BgBlack Color = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow // BgBrown like yellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
// BgDefault revert default BG
|
||||
BgDefault Color = 49
|
||||
)
|
||||
|
||||
// Extra background color 100 - 107(非标准)
|
||||
const (
|
||||
BgDarkGray Color = iota + 100
|
||||
BgLightRed
|
||||
BgLightGreen
|
||||
BgLightYellow
|
||||
BgLightBlue
|
||||
BgLightMagenta
|
||||
BgLightCyan
|
||||
BgLightWhite
|
||||
// BgGray is alias of BgDarkGray
|
||||
BgGray Color = 100
|
||||
)
|
||||
|
||||
// Option settings
|
||||
const (
|
||||
OpReset Color = iota // 0 重置所有设置
|
||||
OpBold // 1 加粗
|
||||
OpFuzzy // 2 模糊(不是所有的终端仿真器都支持)
|
||||
OpItalic // 3 斜体(不是所有的终端仿真器都支持)
|
||||
OpUnderscore // 4 下划线
|
||||
OpBlink // 5 闪烁
|
||||
OpFastBlink // 5 快速闪烁(未广泛支持)
|
||||
OpReverse // 7 颠倒的 交换背景色与前景色
|
||||
OpConcealed // 8 隐匿的
|
||||
OpStrikethrough // 9 删除的,删除线(未广泛支持)
|
||||
)
|
||||
|
||||
// There are basic and light foreground color aliases
|
||||
const (
|
||||
Red = FgRed
|
||||
Cyan = FgCyan
|
||||
Gray = FgDarkGray // is light Black
|
||||
Blue = FgBlue
|
||||
Black = FgBlack
|
||||
Green = FgGreen
|
||||
White = FgWhite
|
||||
Yellow = FgYellow
|
||||
Magenta = FgMagenta
|
||||
|
||||
// special
|
||||
|
||||
Bold = OpBold
|
||||
Normal = FgDefault
|
||||
|
||||
// extra light
|
||||
|
||||
LightRed = FgLightRed
|
||||
LightCyan = FgLightCyan
|
||||
LightBlue = FgLightBlue
|
||||
LightGreen = FgLightGreen
|
||||
LightWhite = FgLightWhite
|
||||
LightYellow = FgLightYellow
|
||||
LightMagenta = FgLightMagenta
|
||||
|
||||
HiRed = FgLightRed
|
||||
HiCyan = FgLightCyan
|
||||
HiBlue = FgLightBlue
|
||||
HiGreen = FgLightGreen
|
||||
HiWhite = FgLightWhite
|
||||
HiYellow = FgLightYellow
|
||||
HiMagenta = FgLightMagenta
|
||||
|
||||
BgHiRed = BgLightRed
|
||||
BgHiCyan = BgLightCyan
|
||||
BgHiBlue = BgLightBlue
|
||||
BgHiGreen = BgLightGreen
|
||||
BgHiWhite = BgLightWhite
|
||||
BgHiYellow = BgLightYellow
|
||||
BgHiMagenta = BgLightMagenta
|
||||
)
|
||||
|
||||
// Bit4 an method for create Color
|
||||
func Bit4(code uint8) Color {
|
||||
return Color(code)
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Color render methods
|
||||
*************************************************************/
|
||||
|
||||
// Name get color code name.
|
||||
func (c Color) Name() string {
|
||||
name, ok := basic2nameMap[uint8(c)]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Text render a text message
|
||||
func (c Color) Text(message string) string {
|
||||
return RenderString(c.String(), message)
|
||||
}
|
||||
|
||||
// Render messages by color setting
|
||||
// Usage:
|
||||
// green := color.FgGreen.Render
|
||||
// fmt.Println(green("message"))
|
||||
func (c Color) Render(a ...interface{}) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Renderln messages by color setting.
|
||||
// like Println, will add spaces for each argument
|
||||
// Usage:
|
||||
// green := color.FgGreen.Renderln
|
||||
// fmt.Println(green("message"))
|
||||
func (c Color) Renderln(a ...interface{}) string {
|
||||
return RenderWithSpaces(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprint render messages by color setting. is alias of the Render()
|
||||
func (c Color) Sprint(a ...interface{}) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf format and render message.
|
||||
// Usage:
|
||||
// green := color.Green.Sprintf
|
||||
// colored := green("message")
|
||||
func (c Color) Sprintf(format string, args ...interface{}) string {
|
||||
return RenderString(c.String(), fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Print messages.
|
||||
// Usage:
|
||||
// color.Green.Print("message")
|
||||
// OR:
|
||||
// green := color.FgGreen.Print
|
||||
// green("message")
|
||||
func (c Color) Print(args ...interface{}) {
|
||||
doPrintV2(c.Code(), fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Printf format and print messages.
|
||||
// Usage:
|
||||
// color.Cyan.Printf("string %s", "arg0")
|
||||
func (c Color) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(c.Code(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println messages with new line
|
||||
func (c Color) Println(a ...interface{}) {
|
||||
doPrintlnV2(c.String(), a)
|
||||
}
|
||||
|
||||
// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
|
||||
// Usage:
|
||||
// lightCyan := Cyan.Light()
|
||||
// lightCyan.Print("message")
|
||||
func (c Color) Light() Color {
|
||||
val := int(c)
|
||||
if val >= 30 && val <= 47 {
|
||||
return Color(uint8(c) + 60)
|
||||
}
|
||||
|
||||
// don't change
|
||||
return c
|
||||
}
|
||||
|
||||
// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
|
||||
// Usage:
|
||||
// cyan := LightCyan.Darken()
|
||||
// cyan.Print("message")
|
||||
func (c Color) Darken() Color {
|
||||
val := int(c)
|
||||
if val >= 90 && val <= 107 {
|
||||
return Color(uint8(c) - 60)
|
||||
}
|
||||
|
||||
// don't change
|
||||
return c
|
||||
}
|
||||
|
||||
// C256 convert 16 color to 256-color code.
|
||||
func (c Color) C256() Color256 {
|
||||
val := uint8(c)
|
||||
if val < 10 { // is option code
|
||||
return emptyC256 // empty
|
||||
}
|
||||
|
||||
var isBg uint8
|
||||
if val >= BgBase && val <= 47 { // is bg
|
||||
isBg = AsBg
|
||||
val = val - 10 // to fg code
|
||||
} else if val >= HiBgBase && val <= 107 { // is hi bg
|
||||
isBg = AsBg
|
||||
val = val - 10 // to fg code
|
||||
}
|
||||
|
||||
if c256, ok := basicTo256Map[val]; ok {
|
||||
return Color256{c256, isBg}
|
||||
}
|
||||
|
||||
// use raw value direct convert
|
||||
return Color256{val}
|
||||
}
|
||||
|
||||
// RGB convert 16 color to 256-color code.
|
||||
func (c Color) RGB() RGBColor {
|
||||
val := uint8(c)
|
||||
if val < 10 { // is option code
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
return HEX(Basic2hex(val))
|
||||
}
|
||||
|
||||
// Code convert to code string. eg "35"
|
||||
func (c Color) Code() string {
|
||||
// return fmt.Sprintf("%d", c)
|
||||
return strconv.Itoa(int(c))
|
||||
}
|
||||
|
||||
// String convert to code string. eg "35"
|
||||
func (c Color) String() string {
|
||||
// return fmt.Sprintf("%d", c)
|
||||
return strconv.Itoa(int(c))
|
||||
}
|
||||
|
||||
// IsValid color value
|
||||
func (c Color) IsValid() bool {
|
||||
return c < 107
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* basic color maps
|
||||
*************************************************************/
|
||||
|
||||
// FgColors foreground colors map
|
||||
var FgColors = map[string]Color{
|
||||
"black": FgBlack,
|
||||
"red": FgRed,
|
||||
"green": FgGreen,
|
||||
"yellow": FgYellow,
|
||||
"blue": FgBlue,
|
||||
"magenta": FgMagenta,
|
||||
"cyan": FgCyan,
|
||||
"white": FgWhite,
|
||||
"default": FgDefault,
|
||||
}
|
||||
|
||||
// BgColors background colors map
|
||||
var BgColors = map[string]Color{
|
||||
"black": BgBlack,
|
||||
"red": BgRed,
|
||||
"green": BgGreen,
|
||||
"yellow": BgYellow,
|
||||
"blue": BgBlue,
|
||||
"magenta": BgMagenta,
|
||||
"cyan": BgCyan,
|
||||
"white": BgWhite,
|
||||
"default": BgDefault,
|
||||
}
|
||||
|
||||
// ExFgColors extra foreground colors map
|
||||
var ExFgColors = map[string]Color{
|
||||
"darkGray": FgDarkGray,
|
||||
"lightRed": FgLightRed,
|
||||
"lightGreen": FgLightGreen,
|
||||
"lightYellow": FgLightYellow,
|
||||
"lightBlue": FgLightBlue,
|
||||
"lightMagenta": FgLightMagenta,
|
||||
"lightCyan": FgLightCyan,
|
||||
"lightWhite": FgLightWhite,
|
||||
}
|
||||
|
||||
// ExBgColors extra background colors map
|
||||
var ExBgColors = map[string]Color{
|
||||
"darkGray": BgDarkGray,
|
||||
"lightRed": BgLightRed,
|
||||
"lightGreen": BgLightGreen,
|
||||
"lightYellow": BgLightYellow,
|
||||
"lightBlue": BgLightBlue,
|
||||
"lightMagenta": BgLightMagenta,
|
||||
"lightCyan": BgLightCyan,
|
||||
"lightWhite": BgLightWhite,
|
||||
}
|
||||
|
||||
// Options color options map
|
||||
// Deprecated
|
||||
// NOTICE: please use AllOptions instead.
|
||||
var Options = AllOptions
|
||||
|
||||
// AllOptions color options map
|
||||
var AllOptions = map[string]Color{
|
||||
"reset": OpReset,
|
||||
"bold": OpBold,
|
||||
"fuzzy": OpFuzzy,
|
||||
"italic": OpItalic,
|
||||
"underscore": OpUnderscore,
|
||||
"blink": OpBlink,
|
||||
"reverse": OpReverse,
|
||||
"concealed": OpConcealed,
|
||||
}
|
||||
|
||||
var (
|
||||
// TODO basic name alias
|
||||
// basicNameAlias = map[string]string{}
|
||||
|
||||
// basic color name to code
|
||||
name2basicMap = initName2basicMap()
|
||||
// basic2nameMap basic color code to name
|
||||
basic2nameMap = map[uint8]string{
|
||||
30: "black",
|
||||
31: "red",
|
||||
32: "green",
|
||||
33: "yellow",
|
||||
34: "blue",
|
||||
35: "magenta",
|
||||
36: "cyan",
|
||||
37: "white",
|
||||
// hi color code
|
||||
90: "lightBlack",
|
||||
91: "lightRed",
|
||||
92: "lightGreen",
|
||||
93: "lightYellow",
|
||||
94: "lightBlue",
|
||||
95: "lightMagenta",
|
||||
96: "lightCyan",
|
||||
97: "lightWhite",
|
||||
// options
|
||||
0: "reset",
|
||||
1: "bold",
|
||||
2: "fuzzy",
|
||||
3: "italic",
|
||||
4: "underscore",
|
||||
5: "blink",
|
||||
7: "reverse",
|
||||
8: "concealed",
|
||||
}
|
||||
)
|
||||
|
||||
// Basic2nameMap data
|
||||
func Basic2nameMap() map[uint8]string {
|
||||
return basic2nameMap
|
||||
}
|
||||
|
||||
func initName2basicMap() map[string]uint8 {
|
||||
n2b := make(map[string]uint8, len(basic2nameMap))
|
||||
for u, s := range basic2nameMap {
|
||||
n2b[s] = u
|
||||
}
|
||||
return n2b
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
from wikipedia, 256 color:
|
||||
ESC[ … 38;5;<n> … m选择前景色
|
||||
ESC[ … 48;5;<n> … m选择背景色
|
||||
0- 7:标准颜色(同 ESC[30–37m)
|
||||
8- 15:高强度颜色(同 ESC[90–97m)
|
||||
16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
232-255:从黑到白的24阶灰度色
|
||||
*/
|
||||
|
||||
// tpl for 8 bit 256 color(`2^8`)
|
||||
//
|
||||
// format:
|
||||
// ESC[ … 38;5;<n> … m // 选择前景色
|
||||
// ESC[ … 48;5;<n> … m // 选择背景色
|
||||
//
|
||||
// example:
|
||||
// fg "\x1b[38;5;242m"
|
||||
// bg "\x1b[48;5;208m"
|
||||
// both "\x1b[38;5;242;48;5;208m"
|
||||
//
|
||||
// links:
|
||||
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位
|
||||
const (
|
||||
TplFg256 = "38;5;%d"
|
||||
TplBg256 = "48;5;%d"
|
||||
Fg256Pfx = "38;5;"
|
||||
Bg256Pfx = "48;5;"
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* 8bit(256) Color: Bit8Color Color256
|
||||
*************************************************************/
|
||||
|
||||
// Color256 256 color (8 bit), uint8 range at 0 - 255
|
||||
//
|
||||
// 颜色值使用10进制和16进制都可 0x98 = 152
|
||||
//
|
||||
// The color consists of two uint8:
|
||||
// 0: color value
|
||||
// 1: color type; Fg=0, Bg=1, >1: unset value
|
||||
//
|
||||
// example:
|
||||
// fg color: [152, 0]
|
||||
// bg color: [152, 1]
|
||||
//
|
||||
// NOTICE: now support 256 color on windows CMD, PowerShell
|
||||
// lint warn - Name starts with package name
|
||||
type Color256 [2]uint8
|
||||
type Bit8Color = Color256 // alias
|
||||
|
||||
var emptyC256 = Color256{1: 99}
|
||||
|
||||
// Bit8 create a color256
|
||||
func Bit8(val uint8, isBg ...bool) Color256 {
|
||||
return C256(val, isBg...)
|
||||
}
|
||||
|
||||
// C256 create a color256
|
||||
func C256(val uint8, isBg ...bool) Color256 {
|
||||
bc := Color256{val}
|
||||
|
||||
// mark is bg color
|
||||
if len(isBg) > 0 && isBg[0] {
|
||||
bc[1] = AsBg
|
||||
}
|
||||
|
||||
return bc
|
||||
}
|
||||
|
||||
// Set terminal by 256 color code
|
||||
func (c Color256) Set() error {
|
||||
return SetTerminal(c.String())
|
||||
}
|
||||
|
||||
// Reset terminal. alias of the ResetTerminal()
|
||||
func (c Color256) Reset() error {
|
||||
return ResetTerminal()
|
||||
}
|
||||
|
||||
// Print print message
|
||||
func (c Color256) Print(a ...interface{}) {
|
||||
doPrintV2(c.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (c Color256) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (c Color256) Println(a ...interface{}) {
|
||||
doPrintlnV2(c.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (c Color256) Sprint(a ...interface{}) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (c Color256) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// C16 convert color-256 to 16 color.
|
||||
func (c Color256) C16() Color {
|
||||
return c.Basic()
|
||||
}
|
||||
|
||||
// Basic convert color-256 to basic 16 color.
|
||||
func (c Color256) Basic() Color {
|
||||
return Color(c[0]) // TODO
|
||||
}
|
||||
|
||||
// RGB convert color-256 to RGB color.
|
||||
func (c Color256) RGB() RGBColor {
|
||||
return RGBFromSlice(C256ToRgb(c[0]), c[1] == AsBg)
|
||||
}
|
||||
|
||||
// RGBColor convert color-256 to RGB color.
|
||||
func (c Color256) RGBColor() RGBColor {
|
||||
return c.RGB()
|
||||
}
|
||||
|
||||
// Value return color value
|
||||
func (c Color256) Value() uint8 {
|
||||
return c[0]
|
||||
}
|
||||
|
||||
// Code convert to color code string. eg: "12"
|
||||
func (c Color256) Code() string {
|
||||
return strconv.Itoa(int(c[0]))
|
||||
}
|
||||
|
||||
// FullCode convert to color code string with prefix. eg: "38;5;12"
|
||||
func (c Color256) FullCode() string {
|
||||
return c.String()
|
||||
}
|
||||
|
||||
// String convert to color code string with prefix. eg: "38;5;12"
|
||||
func (c Color256) String() string {
|
||||
if c[1] == AsFg { // 0 is Fg
|
||||
// return fmt.Sprintf(TplFg256, c[0])
|
||||
return Fg256Pfx + strconv.Itoa(int(c[0]))
|
||||
}
|
||||
|
||||
if c[1] == AsBg { // 1 is Bg
|
||||
// return fmt.Sprintf(TplBg256, c[0])
|
||||
return Bg256Pfx + strconv.Itoa(int(c[0]))
|
||||
}
|
||||
|
||||
return "" // empty
|
||||
}
|
||||
|
||||
// IsFg color
|
||||
func (c Color256) IsFg() bool {
|
||||
return c[1] == AsFg
|
||||
}
|
||||
|
||||
// ToFg 256 color
|
||||
func (c Color256) ToFg() Color256 {
|
||||
c[1] = AsFg
|
||||
return c
|
||||
}
|
||||
|
||||
// IsBg color
|
||||
func (c Color256) IsBg() bool {
|
||||
return c[1] == AsBg
|
||||
}
|
||||
|
||||
// ToBg 256 color
|
||||
func (c Color256) ToBg() Color256 {
|
||||
c[1] = AsBg
|
||||
return c
|
||||
}
|
||||
|
||||
// IsEmpty value
|
||||
func (c Color256) IsEmpty() bool {
|
||||
return c[1] > 1
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* 8bit(256) Style
|
||||
*************************************************************/
|
||||
|
||||
// Style256 definition
|
||||
//
|
||||
// 前/背景色
|
||||
// 都是由两位uint8组成, 第一位是色彩值;
|
||||
// 第二位与 Bit8Color 不一样的是,在这里表示是否设置了值 0 未设置 !=0 已设置
|
||||
type Style256 struct {
|
||||
// p Printer
|
||||
|
||||
// Name of the style
|
||||
Name string
|
||||
// color options of the style
|
||||
opts Opts
|
||||
// fg and bg color
|
||||
fg, bg Color256
|
||||
}
|
||||
|
||||
// S256 create a color256 style
|
||||
// Usage:
|
||||
// s := color.S256()
|
||||
// s := color.S256(132) // fg
|
||||
// s := color.S256(132, 203) // fg and bg
|
||||
func S256(fgAndBg ...uint8) *Style256 {
|
||||
s := &Style256{}
|
||||
vl := len(fgAndBg)
|
||||
if vl > 0 { // with fg
|
||||
s.fg = Color256{fgAndBg[0], 1}
|
||||
|
||||
if vl > 1 { // and with bg
|
||||
s.bg = Color256{fgAndBg[1], 1}
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Set fg and bg color value, can also with color options
|
||||
func (s *Style256) Set(fgVal, bgVal uint8, opts ...Color) *Style256 {
|
||||
s.fg = Color256{fgVal, 1}
|
||||
s.bg = Color256{bgVal, 1}
|
||||
s.opts.Add(opts...)
|
||||
return s
|
||||
}
|
||||
|
||||
// SetBg set bg color value
|
||||
func (s *Style256) SetBg(bgVal uint8) *Style256 {
|
||||
s.bg = Color256{bgVal, 1}
|
||||
return s
|
||||
}
|
||||
|
||||
// SetFg set fg color value
|
||||
func (s *Style256) SetFg(fgVal uint8) *Style256 {
|
||||
s.fg = Color256{fgVal, 1}
|
||||
return s
|
||||
}
|
||||
|
||||
// SetOpts set options
|
||||
func (s *Style256) SetOpts(opts Opts) *Style256 {
|
||||
s.opts = opts
|
||||
return s
|
||||
}
|
||||
|
||||
// AddOpts add options
|
||||
func (s *Style256) AddOpts(opts ...Color) *Style256 {
|
||||
s.opts.Add(opts...)
|
||||
return s
|
||||
}
|
||||
|
||||
// Print message
|
||||
func (s *Style256) Print(a ...interface{}) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (s *Style256) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (s *Style256) Println(a ...interface{}) {
|
||||
doPrintlnV2(s.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (s *Style256) Sprint(a ...interface{}) string {
|
||||
return RenderCode(s.Code(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (s *Style256) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(s.Code(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Code convert to color code string
|
||||
func (s *Style256) Code() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// String convert to color code string
|
||||
func (s *Style256) String() string {
|
||||
var ss []string
|
||||
if s.fg[1] > 0 {
|
||||
ss = append(ss, fmt.Sprintf(TplFg256, s.fg[0]))
|
||||
}
|
||||
|
||||
if s.bg[1] > 0 {
|
||||
ss = append(ss, fmt.Sprintf(TplBg256, s.bg[0]))
|
||||
}
|
||||
|
||||
if s.opts.IsValid() {
|
||||
ss = append(ss, s.opts.String())
|
||||
}
|
||||
|
||||
return strings.Join(ss, ";")
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 24 bit RGB color
|
||||
// RGB:
|
||||
// R 0-255 G 0-255 B 0-255
|
||||
// R 00-FF G 00-FF B 00-FF (16进制)
|
||||
//
|
||||
// Format:
|
||||
// ESC[ … 38;2;<r>;<g>;<b> … m // Select RGB foreground color
|
||||
// ESC[ … 48;2;<r>;<g>;<b> … m // Choose RGB background color
|
||||
//
|
||||
// links:
|
||||
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位
|
||||
//
|
||||
// example:
|
||||
// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m
|
||||
// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m
|
||||
// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m
|
||||
const (
|
||||
TplFgRGB = "38;2;%d;%d;%d"
|
||||
TplBgRGB = "48;2;%d;%d;%d"
|
||||
FgRGBPfx = "38;2;"
|
||||
BgRGBPfx = "48;2;"
|
||||
)
|
||||
|
||||
// mark color is fg or bg.
|
||||
const (
|
||||
AsFg uint8 = iota
|
||||
AsBg
|
||||
)
|
||||
|
||||
// values from https://github.com/go-terminfo/terminfo
|
||||
// var (
|
||||
// RgbaBlack = image_color.RGBA{0, 0, 0, 255}
|
||||
// Red = color.RGBA{205, 0, 0, 255}
|
||||
// Green = color.RGBA{0, 205, 0, 255}
|
||||
// Orange = color.RGBA{205, 205, 0, 255}
|
||||
// Blue = color.RGBA{0, 0, 238, 255}
|
||||
// Magenta = color.RGBA{205, 0, 205, 255}
|
||||
// Cyan = color.RGBA{0, 205, 205, 255}
|
||||
// LightGrey = color.RGBA{229, 229, 229, 255}
|
||||
//
|
||||
// DarkGrey = color.RGBA{127, 127, 127, 255}
|
||||
// LightRed = color.RGBA{255, 0, 0, 255}
|
||||
// LightGreen = color.RGBA{0, 255, 0, 255}
|
||||
// Yellow = color.RGBA{255, 255, 0, 255}
|
||||
// LightBlue = color.RGBA{92, 92, 255, 255}
|
||||
// LightMagenta = color.RGBA{255, 0, 255, 255}
|
||||
// LightCyan = color.RGBA{0, 255, 255, 255}
|
||||
// White = color.RGBA{255, 255, 255, 255}
|
||||
// )
|
||||
|
||||
/*************************************************************
|
||||
* RGB Color(Bit24Color, TrueColor)
|
||||
*************************************************************/
|
||||
|
||||
// RGBColor definition.
|
||||
//
|
||||
// The first to third digits represent the color value.
|
||||
// The last digit represents the foreground(0), background(1), >1 is unset value
|
||||
//
|
||||
// Usage:
|
||||
// // 0, 1, 2 is R,G,B.
|
||||
// // 3rd: Fg=0, Bg=1, >1: unset value
|
||||
// RGBColor{30,144,255, 0}
|
||||
// RGBColor{30,144,255, 1}
|
||||
//
|
||||
// NOTICE: now support RGB color on windows CMD, PowerShell
|
||||
type RGBColor [4]uint8
|
||||
|
||||
// create a empty RGBColor
|
||||
var emptyRGBColor = RGBColor{3: 99}
|
||||
|
||||
// RGB color create.
|
||||
// Usage:
|
||||
// c := RGB(30,144,255)
|
||||
// c := RGB(30,144,255, true)
|
||||
// c.Print("message")
|
||||
func RGB(r, g, b uint8, isBg ...bool) RGBColor {
|
||||
rgb := RGBColor{r, g, b}
|
||||
if len(isBg) > 0 && isBg[0] {
|
||||
rgb[3] = AsBg
|
||||
}
|
||||
|
||||
return rgb
|
||||
}
|
||||
|
||||
// Rgb alias of the RGB()
|
||||
func Rgb(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
|
||||
|
||||
// Bit24 alias of the RGB()
|
||||
func Bit24(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
|
||||
|
||||
// RGBFromSlice quick RGBColor from slice
|
||||
func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
|
||||
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
|
||||
}
|
||||
|
||||
// HEX create RGB color from a HEX color string.
|
||||
// Usage:
|
||||
// c := HEX("ccc") // rgb: [204 204 204]
|
||||
// c := HEX("aabbcc") // rgb: [170 187 204]
|
||||
// c := HEX("#aabbcc")
|
||||
// c := HEX("0xaabbcc")
|
||||
// c.Print("message")
|
||||
func HEX(hex string, isBg ...bool) RGBColor {
|
||||
if rgb := HexToRgb(hex); len(rgb) > 0 {
|
||||
return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...)
|
||||
}
|
||||
|
||||
// mark is empty
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
// Hex alias of the HEX()
|
||||
func Hex(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
|
||||
|
||||
// RGBFromString create RGB color from a string.
|
||||
// Usage:
|
||||
// c := RGBFromString("170,187,204")
|
||||
// c.Print("message")
|
||||
func RGBFromString(rgb string, isBg ...bool) RGBColor {
|
||||
ss := stringToArr(rgb, ",")
|
||||
if len(ss) != 3 {
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
var ar [3]int
|
||||
for i, val := range ss {
|
||||
iv, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
ar[i] = iv
|
||||
}
|
||||
|
||||
return RGB(uint8(ar[0]), uint8(ar[1]), uint8(ar[2]), isBg...)
|
||||
}
|
||||
|
||||
// Set terminal by rgb/true color code
|
||||
func (c RGBColor) Set() error {
|
||||
return SetTerminal(c.String())
|
||||
}
|
||||
|
||||
// Reset terminal. alias of the ResetTerminal()
|
||||
func (c RGBColor) Reset() error {
|
||||
return ResetTerminal()
|
||||
}
|
||||
|
||||
// Print print message
|
||||
func (c RGBColor) Print(a ...interface{}) {
|
||||
doPrintV2(c.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (c RGBColor) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (c RGBColor) Println(a ...interface{}) {
|
||||
doPrintlnV2(c.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (c RGBColor) Sprint(a ...interface{}) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (c RGBColor) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Values to RGB values
|
||||
func (c RGBColor) Values() []int {
|
||||
return []int{int(c[0]), int(c[1]), int(c[2])}
|
||||
}
|
||||
|
||||
// Code to color code string without prefix. eg: "204;123;56"
|
||||
func (c RGBColor) Code() string {
|
||||
return fmt.Sprintf("%d;%d;%d", c[0], c[1], c[2])
|
||||
}
|
||||
|
||||
// Hex color rgb to hex string. as in "ff0080".
|
||||
func (c RGBColor) Hex() string {
|
||||
return fmt.Sprintf("%02x%02x%02x", c[0], c[1], c[2])
|
||||
}
|
||||
|
||||
// FullCode to color code string with prefix
|
||||
func (c RGBColor) FullCode() string {
|
||||
return c.String()
|
||||
}
|
||||
|
||||
// String to color code string with prefix. eg: "38;2;204;123;56"
|
||||
func (c RGBColor) String() string {
|
||||
if c[3] == AsFg {
|
||||
return fmt.Sprintf(TplFgRGB, c[0], c[1], c[2])
|
||||
}
|
||||
|
||||
if c[3] == AsBg {
|
||||
return fmt.Sprintf(TplBgRGB, c[0], c[1], c[2])
|
||||
}
|
||||
|
||||
// c[3] > 1 is empty
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsEmpty value
|
||||
func (c RGBColor) IsEmpty() bool {
|
||||
return c[3] > AsBg
|
||||
}
|
||||
|
||||
// IsValid value
|
||||
// func (c RGBColor) IsValid() bool {
|
||||
// return c[3] <= AsBg
|
||||
// }
|
||||
|
||||
// C256 returns the closest approximate 256 (8 bit) color
|
||||
func (c RGBColor) C256() Color256 {
|
||||
return C256(RgbTo256(c[0], c[1], c[2]), c[3] == AsBg)
|
||||
}
|
||||
|
||||
// Basic returns the closest approximate 16 (4 bit) color
|
||||
func (c RGBColor) Basic() Color {
|
||||
// return Color(RgbToAnsi(c[0], c[1], c[2], c[3] == AsBg))
|
||||
return Color(Rgb2basic(c[0], c[1], c[2], c[3] == AsBg))
|
||||
}
|
||||
|
||||
// Color returns the closest approximate 16 (4 bit) color
|
||||
func (c RGBColor) Color() Color { return c.Basic() }
|
||||
|
||||
// C16 returns the closest approximate 16 (4 bit) color
|
||||
func (c RGBColor) C16() Color { return c.Basic() }
|
||||
|
||||
/*************************************************************
|
||||
* RGB Style
|
||||
*************************************************************/
|
||||
|
||||
// RGBStyle definition.
|
||||
//
|
||||
// Foreground/Background color
|
||||
// All are composed of 4 digits uint8, the first three digits are the color value;
|
||||
// The last bit is different from RGBColor, here it indicates whether the value is set.
|
||||
// - 1 Has been set
|
||||
// - ^1 Not set
|
||||
type RGBStyle struct {
|
||||
// Name of the style
|
||||
Name string
|
||||
// color options of the style
|
||||
opts Opts
|
||||
// fg and bg color
|
||||
fg, bg RGBColor
|
||||
}
|
||||
|
||||
// NewRGBStyle create a RGBStyle.
|
||||
func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle {
|
||||
s := &RGBStyle{}
|
||||
if len(bg) > 0 {
|
||||
s.SetBg(bg[0])
|
||||
}
|
||||
|
||||
return s.SetFg(fg)
|
||||
}
|
||||
|
||||
// HEXStyle create a RGBStyle from HEX color string.
|
||||
// Usage:
|
||||
// s := HEXStyle("aabbcc", "eee")
|
||||
// s.Print("message")
|
||||
func HEXStyle(fg string, bg ...string) *RGBStyle {
|
||||
s := &RGBStyle{}
|
||||
if len(bg) > 0 {
|
||||
s.SetBg(HEX(bg[0]))
|
||||
}
|
||||
|
||||
if len(fg) > 0 {
|
||||
s.SetFg(HEX(fg))
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// RGBStyleFromString create a RGBStyle from color value string.
|
||||
// Usage:
|
||||
// s := RGBStyleFromString("170,187,204", "70,87,4")
|
||||
// s.Print("message")
|
||||
func RGBStyleFromString(fg string, bg ...string) *RGBStyle {
|
||||
s := &RGBStyle{}
|
||||
if len(bg) > 0 {
|
||||
s.SetBg(RGBFromString(bg[0]))
|
||||
}
|
||||
|
||||
return s.SetFg(RGBFromString(fg))
|
||||
}
|
||||
|
||||
// Set fg and bg color, can also with color options
|
||||
func (s *RGBStyle) Set(fg, bg RGBColor, opts ...Color) *RGBStyle {
|
||||
return s.SetFg(fg).SetBg(bg).SetOpts(opts)
|
||||
}
|
||||
|
||||
// SetFg set fg color
|
||||
func (s *RGBStyle) SetFg(fg RGBColor) *RGBStyle {
|
||||
fg[3] = 1 // add fixed value, mark is valid
|
||||
s.fg = fg
|
||||
return s
|
||||
}
|
||||
|
||||
// SetBg set bg color
|
||||
func (s *RGBStyle) SetBg(bg RGBColor) *RGBStyle {
|
||||
bg[3] = 1 // add fixed value, mark is valid
|
||||
s.bg = bg
|
||||
return s
|
||||
}
|
||||
|
||||
// SetOpts set color options
|
||||
func (s *RGBStyle) SetOpts(opts Opts) *RGBStyle {
|
||||
s.opts = opts
|
||||
return s
|
||||
}
|
||||
|
||||
// AddOpts add options
|
||||
func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle {
|
||||
s.opts.Add(opts...)
|
||||
return s
|
||||
}
|
||||
|
||||
// Print print message
|
||||
func (s *RGBStyle) Print(a ...interface{}) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (s *RGBStyle) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (s *RGBStyle) Println(a ...interface{}) {
|
||||
doPrintlnV2(s.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (s *RGBStyle) Sprint(a ...interface{}) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (s *RGBStyle) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Code convert to color code string
|
||||
func (s *RGBStyle) Code() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// FullCode convert to color code string
|
||||
func (s *RGBStyle) FullCode() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// String convert to color code string
|
||||
func (s *RGBStyle) String() string {
|
||||
var ss []string
|
||||
// last value ensure is enable.
|
||||
if s.fg[3] == 1 {
|
||||
ss = append(ss, fmt.Sprintf(TplFgRGB, s.fg[0], s.fg[1], s.fg[2]))
|
||||
}
|
||||
|
||||
if s.bg[3] == 1 {
|
||||
ss = append(ss, fmt.Sprintf(TplBgRGB, s.bg[0], s.bg[1], s.bg[2]))
|
||||
}
|
||||
|
||||
if s.opts.IsValid() {
|
||||
ss = append(ss, s.opts.String())
|
||||
}
|
||||
|
||||
return strings.Join(ss, ";")
|
||||
}
|
||||
|
||||
// IsEmpty style
|
||||
func (s *RGBStyle) IsEmpty() bool {
|
||||
return s.fg[3] != 1 && s.bg[3] != 1
|
||||
}
|
|
@ -0,0 +1,427 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// output colored text like use html tag. (not support windows cmd)
|
||||
const (
|
||||
// MatchExpr regex to match color tags
|
||||
//
|
||||
// Notice: golang 不支持反向引用. 即不支持使用 \1 引用第一个匹配 ([a-z=;]+)
|
||||
// MatchExpr = `<([a-z=;]+)>(.*?)<\/\1>`
|
||||
// 所以调整一下 统一使用 `</>` 来结束标签,例如 "<info>some text</>"
|
||||
//
|
||||
// allow custom attrs, eg: "<fg=white;bg=blue;op=bold>content</>"
|
||||
// (?s:...) s - 让 "." 匹配换行
|
||||
MatchExpr = `<([0-9a-zA-Z_=,;]+)>(?s:(.*?))<\/>`
|
||||
|
||||
// AttrExpr regex to match custom color attributes
|
||||
// eg: "<fg=white;bg=blue;op=bold>content</>"
|
||||
AttrExpr = `(fg|bg|op)[\s]*=[\s]*([0-9a-zA-Z,]+);?`
|
||||
|
||||
// StripExpr regex used for removing color tags
|
||||
// StripExpr = `<[\/]?[a-zA-Z=;]+>`
|
||||
// 随着上面的做一些调整
|
||||
StripExpr = `<[\/]?[0-9a-zA-Z_=,;]*>`
|
||||
)
|
||||
|
||||
var (
|
||||
attrRegex = regexp.MustCompile(AttrExpr)
|
||||
matchRegex = regexp.MustCompile(MatchExpr)
|
||||
stripRegex = regexp.MustCompile(StripExpr)
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* internal defined color tags
|
||||
*************************************************************/
|
||||
|
||||
// There are internal defined color tags
|
||||
// Usage: <tag>content text</>
|
||||
// @notice 加 0 在前面是为了防止之前的影响到现在的设置
|
||||
var colorTags = map[string]string{
|
||||
// basic tags
|
||||
"red": "0;31",
|
||||
"red1": "1;31", // with bold
|
||||
"redB": "1;31",
|
||||
"red_b": "1;31",
|
||||
"blue": "0;34",
|
||||
"blue1": "1;34", // with bold
|
||||
"blueB": "1;34",
|
||||
"blue_b": "1;34",
|
||||
"cyan": "0;36",
|
||||
"cyan1": "1;36", // with bold
|
||||
"cyanB": "1;36",
|
||||
"cyan_b": "1;36",
|
||||
"green": "0;32",
|
||||
"green1": "1;32", // with bold
|
||||
"greenB": "1;32",
|
||||
"green_b": "1;32",
|
||||
"black": "0;30",
|
||||
"white": "1;37",
|
||||
"default": "0;39", // no color
|
||||
"normal": "0;39", // no color
|
||||
"brown": "0;33", // #A52A2A
|
||||
"yellow": "0;33",
|
||||
"ylw0": "0;33",
|
||||
"yellowB": "1;33", // with bold
|
||||
"ylw1": "1;33",
|
||||
"ylwB": "1;33",
|
||||
"magenta": "0;35",
|
||||
"mga": "0;35", // short name
|
||||
"magentaB": "1;35", // with bold
|
||||
"mgb": "1;35",
|
||||
"mgaB": "1;35",
|
||||
|
||||
// light/hi tags
|
||||
|
||||
"gray": "0;90",
|
||||
"darkGray": "0;90",
|
||||
"dark_gray": "0;90",
|
||||
"lightYellow": "0;93",
|
||||
"light_yellow": "0;93",
|
||||
"hiYellow": "0;93",
|
||||
"hi_yellow": "0;93",
|
||||
"hiYellowB": "1;93", // with bold
|
||||
"hi_yellow_b": "1;93",
|
||||
"lightMagenta": "0;95",
|
||||
"light_magenta": "0;95",
|
||||
"hiMagenta": "0;95",
|
||||
"hi_magenta": "0;95",
|
||||
"lightMagentaB": "1;95", // with bold
|
||||
"hiMagentaB": "1;95", // with bold
|
||||
"hi_magenta_b": "1;95",
|
||||
"lightRed": "0;91",
|
||||
"light_red": "0;91",
|
||||
"hiRed": "0;91",
|
||||
"hi_red": "0;91",
|
||||
"lightRedB": "1;91", // with bold
|
||||
"light_red_b": "1;91",
|
||||
"hi_red_b": "1;91",
|
||||
"lightGreen": "0;92",
|
||||
"light_green": "0;92",
|
||||
"hiGreen": "0;92",
|
||||
"hi_green": "0;92",
|
||||
"lightGreenB": "1;92",
|
||||
"light_green_b": "1;92",
|
||||
"hi_green_b": "1;92",
|
||||
"lightBlue": "0;94",
|
||||
"light_blue": "0;94",
|
||||
"hiBlue": "0;94",
|
||||
"hi_blue": "0;94",
|
||||
"lightBlueB": "1;94",
|
||||
"light_blue_b": "1;94",
|
||||
"hi_blue_b": "1;94",
|
||||
"lightCyan": "0;96",
|
||||
"light_cyan": "0;96",
|
||||
"hiCyan": "0;96",
|
||||
"hi_cyan": "0;96",
|
||||
"lightCyanB": "1;96",
|
||||
"light_cyan_b": "1;96",
|
||||
"hi_cyan_b": "1;96",
|
||||
"lightWhite": "0;97;40",
|
||||
"light_white": "0;97;40",
|
||||
|
||||
// option
|
||||
"bold": "1",
|
||||
"b": "1",
|
||||
"underscore": "4",
|
||||
"us": "4", // short name for 'underscore'
|
||||
"reverse": "7",
|
||||
|
||||
// alert tags, like bootstrap's alert
|
||||
"suc": "1;32", // same "green" and "bold"
|
||||
"success": "1;32",
|
||||
"info": "0;32", // same "green",
|
||||
"comment": "0;33", // same "brown"
|
||||
"note": "36;1",
|
||||
"notice": "36;4",
|
||||
"warn": "0;1;33",
|
||||
"warning": "0;30;43",
|
||||
"primary": "0;34",
|
||||
"danger": "1;31", // same "red" but add bold
|
||||
"err": "97;41",
|
||||
"error": "97;41", // fg light white; bg red
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* parse color tags
|
||||
*************************************************************/
|
||||
|
||||
var (
|
||||
tagParser = TagParser{}
|
||||
rxNumStr = regexp.MustCompile("^[0-9]{1,3}$")
|
||||
rxHexCode = regexp.MustCompile("^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
|
||||
)
|
||||
|
||||
// TagParser struct
|
||||
type TagParser struct {
|
||||
disable bool
|
||||
}
|
||||
|
||||
// NewTagParser create
|
||||
func NewTagParser() *TagParser {
|
||||
return &TagParser{}
|
||||
}
|
||||
|
||||
// func (tp *TagParser) Disable() *TagParser {
|
||||
// tp.disable = true
|
||||
// return tp
|
||||
// }
|
||||
|
||||
// ParseByEnv parse given string. will check package setting.
|
||||
func (tp *TagParser) ParseByEnv(str string) string {
|
||||
// disable handler TAG
|
||||
if !RenderTag {
|
||||
return str
|
||||
}
|
||||
|
||||
// disable OR not support color
|
||||
if !Enable || !SupportColor() {
|
||||
return ClearTag(str)
|
||||
}
|
||||
|
||||
return tp.Parse(str)
|
||||
}
|
||||
|
||||
// Parse parse given string, replace color tag and return rendered string
|
||||
func (tp *TagParser) Parse(str string) string {
|
||||
// not contains color tag
|
||||
if !strings.Contains(str, "</>") {
|
||||
return str
|
||||
}
|
||||
|
||||
// find color tags by regex. str eg: "<fg=white;bg=blue;op=bold>content</>"
|
||||
matched := matchRegex.FindAllStringSubmatch(str, -1)
|
||||
|
||||
// item: 0 full text 1 tag name 2 tag content
|
||||
for _, item := range matched {
|
||||
full, tag, content := item[0], item[1], item[2]
|
||||
|
||||
// use defined tag name: "<info>content</>" -> tag: "info"
|
||||
if !strings.ContainsRune(tag, '=') {
|
||||
code := colorTags[tag]
|
||||
if len(code) > 0 {
|
||||
now := RenderString(code, content)
|
||||
// old := WrapTag(content, tag) is equals to var 'full'
|
||||
str = strings.Replace(str, full, now, 1)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// custom color in tag
|
||||
// - basic: "fg=white;bg=blue;op=bold"
|
||||
if code := ParseCodeFromAttr(tag); len(code) > 0 {
|
||||
now := RenderString(code, content)
|
||||
str = strings.Replace(str, full, now, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// func (tp *TagParser) ParseAttr(attr string) (code string) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// ReplaceTag parse string, replace color tag and return rendered string
|
||||
func ReplaceTag(str string) string {
|
||||
return tagParser.ParseByEnv(str)
|
||||
}
|
||||
|
||||
// ParseCodeFromAttr parse color attributes.
|
||||
//
|
||||
// attr format:
|
||||
// // VALUE please see var: FgColors, BgColors, AllOptions
|
||||
// "fg=VALUE;bg=VALUE;op=VALUE"
|
||||
// 16 color:
|
||||
// "fg=yellow"
|
||||
// "bg=red"
|
||||
// "op=bold,underscore" option is allow multi value
|
||||
// "fg=white;bg=blue;op=bold"
|
||||
// "fg=white;op=bold,underscore"
|
||||
// 256 color:
|
||||
// "fg=167"
|
||||
// "fg=167;bg=23"
|
||||
// "fg=167;bg=23;op=bold"
|
||||
// true color:
|
||||
// // hex
|
||||
// "fg=fc1cac"
|
||||
// "fg=fc1cac;bg=c2c3c4"
|
||||
// // r,g,b
|
||||
// "fg=23,45,214"
|
||||
// "fg=23,45,214;bg=109,99,88"
|
||||
func ParseCodeFromAttr(attr string) (code string) {
|
||||
if !strings.ContainsRune(attr, '=') {
|
||||
return
|
||||
}
|
||||
|
||||
attr = strings.Trim(attr, ";=,")
|
||||
if len(attr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var codes []string
|
||||
matched := attrRegex.FindAllStringSubmatch(attr, -1)
|
||||
|
||||
for _, item := range matched {
|
||||
pos, val := item[1], item[2]
|
||||
switch pos {
|
||||
case "fg":
|
||||
if c, ok := FgColors[val]; ok { // basic
|
||||
codes = append(codes, c.String())
|
||||
} else if c, ok := ExFgColors[val]; ok { // extra
|
||||
codes = append(codes, c.String())
|
||||
} else if code := rgbHex256toCode(val, false); code != "" {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
case "bg":
|
||||
if c, ok := BgColors[val]; ok { // basic bg
|
||||
codes = append(codes, c.String())
|
||||
} else if c, ok := ExBgColors[val]; ok { // extra bg
|
||||
codes = append(codes, c.String())
|
||||
} else if code := rgbHex256toCode(val, true); code != "" {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
case "op": // options allow multi value
|
||||
if strings.Contains(val, ",") {
|
||||
ns := strings.Split(val, ",")
|
||||
for _, n := range ns {
|
||||
if c, ok := AllOptions[n]; ok {
|
||||
codes = append(codes, c.String())
|
||||
}
|
||||
}
|
||||
} else if c, ok := AllOptions[val]; ok {
|
||||
codes = append(codes, c.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(codes, ";")
|
||||
}
|
||||
|
||||
func rgbHex256toCode(val string, isBg bool) (code string) {
|
||||
if len(val) == 6 && rxHexCode.MatchString(val) { // hex: "fc1cac"
|
||||
code = HEX(val, isBg).String()
|
||||
} else if strings.ContainsRune(val, ',') { // rgb: "231,178,161"
|
||||
code = strings.Replace(val, ",", ";", -1)
|
||||
if isBg {
|
||||
code = BgRGBPfx + code
|
||||
} else {
|
||||
code = FgRGBPfx + code
|
||||
}
|
||||
} else if len(val) < 4 && rxNumStr.MatchString(val) { // 256 code
|
||||
if isBg {
|
||||
code = Bg256Pfx + val
|
||||
} else {
|
||||
code = Fg256Pfx + val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ClearTag clear all tag for a string
|
||||
func ClearTag(s string) string {
|
||||
if !strings.Contains(s, "</>") {
|
||||
return s
|
||||
}
|
||||
|
||||
return stripRegex.ReplaceAllString(s, "")
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* helper methods
|
||||
*************************************************************/
|
||||
|
||||
// GetTagCode get color code by tag name
|
||||
func GetTagCode(name string) string {
|
||||
return colorTags[name]
|
||||
}
|
||||
|
||||
// ApplyTag for messages
|
||||
func ApplyTag(tag string, a ...interface{}) string {
|
||||
return RenderCode(GetTagCode(tag), a...)
|
||||
}
|
||||
|
||||
// WrapTag wrap a tag for a string "<tag>content</>"
|
||||
func WrapTag(s string, tag string) string {
|
||||
if s == "" || tag == "" {
|
||||
return s
|
||||
}
|
||||
|
||||
return fmt.Sprintf("<%s>%s</>", tag, s)
|
||||
}
|
||||
|
||||
// GetColorTags get all internal color tags
|
||||
func GetColorTags() map[string]string {
|
||||
return colorTags
|
||||
}
|
||||
|
||||
// IsDefinedTag is defined tag name
|
||||
func IsDefinedTag(name string) bool {
|
||||
_, ok := colorTags[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Tag extra
|
||||
*************************************************************/
|
||||
|
||||
// Tag value is a defined style name
|
||||
// Usage:
|
||||
// Tag("info").Println("message")
|
||||
type Tag string
|
||||
|
||||
// Print messages
|
||||
func (tg Tag) Print(a ...interface{}) {
|
||||
name := string(tg)
|
||||
str := fmt.Sprint(a...)
|
||||
|
||||
if stl := GetStyle(name); !stl.IsEmpty() {
|
||||
stl.Print(str)
|
||||
} else {
|
||||
doPrintV2(GetTagCode(name), str)
|
||||
}
|
||||
}
|
||||
|
||||
// Printf format and print messages
|
||||
func (tg Tag) Printf(format string, a ...interface{}) {
|
||||
name := string(tg)
|
||||
str := fmt.Sprintf(format, a...)
|
||||
|
||||
if stl := GetStyle(name); !stl.IsEmpty() {
|
||||
stl.Print(str)
|
||||
} else {
|
||||
doPrintV2(GetTagCode(name), str)
|
||||
}
|
||||
}
|
||||
|
||||
// Println messages line
|
||||
func (tg Tag) Println(a ...interface{}) {
|
||||
name := string(tg)
|
||||
if stl := GetStyle(name); !stl.IsEmpty() {
|
||||
stl.Println(a...)
|
||||
} else {
|
||||
doPrintlnV2(GetTagCode(name), a)
|
||||
}
|
||||
}
|
||||
|
||||
// Sprint render messages
|
||||
func (tg Tag) Sprint(a ...interface{}) string {
|
||||
name := string(tg)
|
||||
// if stl := GetStyle(name); !stl.IsEmpty() {
|
||||
// return stl.Render(args...)
|
||||
// }
|
||||
|
||||
return RenderCode(GetTagCode(name), a...)
|
||||
}
|
||||
|
||||
// Sprintf format and render messages
|
||||
func (tg Tag) Sprintf(format string, a ...interface{}) string {
|
||||
tag := string(tg)
|
||||
str := fmt.Sprintf(format, a...)
|
||||
|
||||
return RenderString(GetTagCode(tag), str)
|
||||
}
|
|
@ -0,0 +1,593 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// ---------- basic(16) <=> 256 color convert ----------
|
||||
basicTo256Map = map[uint8]uint8{
|
||||
30: 0, // black 000000
|
||||
31: 160, // red c51e14
|
||||
32: 34, // green 1dc121
|
||||
33: 184, // yellow c7c329
|
||||
34: 20, // blue 0a2fc4
|
||||
35: 170, // magenta c839c5
|
||||
36: 44, // cyan 20c5c6
|
||||
37: 188, // white c7c7c7
|
||||
90: 59, // lightBlack 686868
|
||||
91: 203, // lightRed fd6f6b
|
||||
92: 83, // lightGreen 67f86f
|
||||
93: 227, // lightYellow fffa72
|
||||
94: 69, // lightBlue 6a76fb
|
||||
95: 213, // lightMagenta fd7cfc
|
||||
96: 87, // lightCyan 68fdfe
|
||||
97: 15, // lightWhite ffffff
|
||||
}
|
||||
|
||||
// ---------- basic(16) <=> RGB color convert ----------
|
||||
// refer from Hyper app
|
||||
basic2hexMap = map[uint8]string{
|
||||
30: "000000", // black
|
||||
31: "c51e14", // red
|
||||
32: "1dc121", // green
|
||||
33: "c7c329", // yellow
|
||||
34: "0a2fc4", // blue
|
||||
35: "c839c5", // magenta
|
||||
36: "20c5c6", // cyan
|
||||
37: "c7c7c7", // white
|
||||
90: "686868", // lightBlack/darkGray
|
||||
91: "fd6f6b", // lightRed
|
||||
92: "67f86f", // lightGreen
|
||||
93: "fffa72", // lightYellow
|
||||
94: "6a76fb", // lightBlue
|
||||
95: "fd7cfc", // lightMagenta
|
||||
96: "68fdfe", // lightCyan
|
||||
97: "ffffff", // lightWhite
|
||||
}
|
||||
// will convert data from basic2hexMap
|
||||
hex2basicMap = initHex2basicMap()
|
||||
|
||||
// ---------- 256 <=> RGB color convert ----------
|
||||
// adapted from https://gist.github.com/MicahElliott/719710
|
||||
|
||||
c256ToHexMap = init256ToHexMap()
|
||||
|
||||
// rgb to 256 color look-up table
|
||||
// RGB hex => 256 code
|
||||
hexTo256Table = map[string]uint8{
|
||||
// Primary 3-bit (8 colors). Unique representation!
|
||||
"000000": 0,
|
||||
"800000": 1,
|
||||
"008000": 2,
|
||||
"808000": 3,
|
||||
"000080": 4,
|
||||
"800080": 5,
|
||||
"008080": 6,
|
||||
"c0c0c0": 7,
|
||||
|
||||
// Equivalent "bright" versions of original 8 colors.
|
||||
"808080": 8,
|
||||
"ff0000": 9,
|
||||
"00ff00": 10,
|
||||
"ffff00": 11,
|
||||
"0000ff": 12,
|
||||
"ff00ff": 13,
|
||||
"00ffff": 14,
|
||||
"ffffff": 15,
|
||||
|
||||
// values commented out below are duplicates from the prior sections
|
||||
|
||||
// Strictly ascending.
|
||||
// "000000": 16,
|
||||
"000001": 16, // up: avoid key conflicts, value + 1
|
||||
"00005f": 17,
|
||||
"000087": 18,
|
||||
"0000af": 19,
|
||||
"0000d7": 20,
|
||||
// "0000ff": 21,
|
||||
"0000fe": 21, // up: avoid key conflicts, value - 1
|
||||
"005f00": 22,
|
||||
"005f5f": 23,
|
||||
"005f87": 24,
|
||||
"005faf": 25,
|
||||
"005fd7": 26,
|
||||
"005fff": 27,
|
||||
"008700": 28,
|
||||
"00875f": 29,
|
||||
"008787": 30,
|
||||
"0087af": 31,
|
||||
"0087d7": 32,
|
||||
"0087ff": 33,
|
||||
"00af00": 34,
|
||||
"00af5f": 35,
|
||||
"00af87": 36,
|
||||
"00afaf": 37,
|
||||
"00afd7": 38,
|
||||
"00afff": 39,
|
||||
"00d700": 40,
|
||||
"00d75f": 41,
|
||||
"00d787": 42,
|
||||
"00d7af": 43,
|
||||
"00d7d7": 44,
|
||||
"00d7ff": 45,
|
||||
// "00ff00": 46,
|
||||
"00ff01": 46, // up: avoid key conflicts, value + 1
|
||||
"00ff5f": 47,
|
||||
"00ff87": 48,
|
||||
"00ffaf": 49,
|
||||
"00ffd7": 50,
|
||||
// "00ffff": 51,
|
||||
"00fffe": 51, // up: avoid key conflicts, value - 1
|
||||
"5f0000": 52,
|
||||
"5f005f": 53,
|
||||
"5f0087": 54,
|
||||
"5f00af": 55,
|
||||
"5f00d7": 56,
|
||||
"5f00ff": 57,
|
||||
"5f5f00": 58,
|
||||
"5f5f5f": 59,
|
||||
"5f5f87": 60,
|
||||
"5f5faf": 61,
|
||||
"5f5fd7": 62,
|
||||
"5f5fff": 63,
|
||||
"5f8700": 64,
|
||||
"5f875f": 65,
|
||||
"5f8787": 66,
|
||||
"5f87af": 67,
|
||||
"5f87d7": 68,
|
||||
"5f87ff": 69,
|
||||
"5faf00": 70,
|
||||
"5faf5f": 71,
|
||||
"5faf87": 72,
|
||||
"5fafaf": 73,
|
||||
"5fafd7": 74,
|
||||
"5fafff": 75,
|
||||
"5fd700": 76,
|
||||
"5fd75f": 77,
|
||||
"5fd787": 78,
|
||||
"5fd7af": 79,
|
||||
"5fd7d7": 80,
|
||||
"5fd7ff": 81,
|
||||
"5fff00": 82,
|
||||
"5fff5f": 83,
|
||||
"5fff87": 84,
|
||||
"5fffaf": 85,
|
||||
"5fffd7": 86,
|
||||
"5fffff": 87,
|
||||
"870000": 88,
|
||||
"87005f": 89,
|
||||
"870087": 90,
|
||||
"8700af": 91,
|
||||
"8700d7": 92,
|
||||
"8700ff": 93,
|
||||
"875f00": 94,
|
||||
"875f5f": 95,
|
||||
"875f87": 96,
|
||||
"875faf": 97,
|
||||
"875fd7": 98,
|
||||
"875fff": 99,
|
||||
"878700": 100,
|
||||
"87875f": 101,
|
||||
"878787": 102,
|
||||
"8787af": 103,
|
||||
"8787d7": 104,
|
||||
"8787ff": 105,
|
||||
"87af00": 106,
|
||||
"87af5f": 107,
|
||||
"87af87": 108,
|
||||
"87afaf": 109,
|
||||
"87afd7": 110,
|
||||
"87afff": 111,
|
||||
"87d700": 112,
|
||||
"87d75f": 113,
|
||||
"87d787": 114,
|
||||
"87d7af": 115,
|
||||
"87d7d7": 116,
|
||||
"87d7ff": 117,
|
||||
"87ff00": 118,
|
||||
"87ff5f": 119,
|
||||
"87ff87": 120,
|
||||
"87ffaf": 121,
|
||||
"87ffd7": 122,
|
||||
"87ffff": 123,
|
||||
"af0000": 124,
|
||||
"af005f": 125,
|
||||
"af0087": 126,
|
||||
"af00af": 127,
|
||||
"af00d7": 128,
|
||||
"af00ff": 129,
|
||||
"af5f00": 130,
|
||||
"af5f5f": 131,
|
||||
"af5f87": 132,
|
||||
"af5faf": 133,
|
||||
"af5fd7": 134,
|
||||
"af5fff": 135,
|
||||
"af8700": 136,
|
||||
"af875f": 137,
|
||||
"af8787": 138,
|
||||
"af87af": 139,
|
||||
"af87d7": 140,
|
||||
"af87ff": 141,
|
||||
"afaf00": 142,
|
||||
"afaf5f": 143,
|
||||
"afaf87": 144,
|
||||
"afafaf": 145,
|
||||
"afafd7": 146,
|
||||
"afafff": 147,
|
||||
"afd700": 148,
|
||||
"afd75f": 149,
|
||||
"afd787": 150,
|
||||
"afd7af": 151,
|
||||
"afd7d7": 152,
|
||||
"afd7ff": 153,
|
||||
"afff00": 154,
|
||||
"afff5f": 155,
|
||||
"afff87": 156,
|
||||
"afffaf": 157,
|
||||
"afffd7": 158,
|
||||
"afffff": 159,
|
||||
"d70000": 160,
|
||||
"d7005f": 161,
|
||||
"d70087": 162,
|
||||
"d700af": 163,
|
||||
"d700d7": 164,
|
||||
"d700ff": 165,
|
||||
"d75f00": 166,
|
||||
"d75f5f": 167,
|
||||
"d75f87": 168,
|
||||
"d75faf": 169,
|
||||
"d75fd7": 170,
|
||||
"d75fff": 171,
|
||||
"d78700": 172,
|
||||
"d7875f": 173,
|
||||
"d78787": 174,
|
||||
"d787af": 175,
|
||||
"d787d7": 176,
|
||||
"d787ff": 177,
|
||||
"d7af00": 178,
|
||||
"d7af5f": 179,
|
||||
"d7af87": 180,
|
||||
"d7afaf": 181,
|
||||
"d7afd7": 182,
|
||||
"d7afff": 183,
|
||||
"d7d700": 184,
|
||||
"d7d75f": 185,
|
||||
"d7d787": 186,
|
||||
"d7d7af": 187,
|
||||
"d7d7d7": 188,
|
||||
"d7d7ff": 189,
|
||||
"d7ff00": 190,
|
||||
"d7ff5f": 191,
|
||||
"d7ff87": 192,
|
||||
"d7ffaf": 193,
|
||||
"d7ffd7": 194,
|
||||
"d7ffff": 195,
|
||||
// "ff0000": 196,
|
||||
"ff0001": 196, // up: avoid key conflicts, value + 1
|
||||
"ff005f": 197,
|
||||
"ff0087": 198,
|
||||
"ff00af": 199,
|
||||
"ff00d7": 200,
|
||||
// "ff00ff": 201,
|
||||
"ff00fe": 201, // up: avoid key conflicts, value - 1
|
||||
"ff5f00": 202,
|
||||
"ff5f5f": 203,
|
||||
"ff5f87": 204,
|
||||
"ff5faf": 205,
|
||||
"ff5fd7": 206,
|
||||
"ff5fff": 207,
|
||||
"ff8700": 208,
|
||||
"ff875f": 209,
|
||||
"ff8787": 210,
|
||||
"ff87af": 211,
|
||||
"ff87d7": 212,
|
||||
"ff87ff": 213,
|
||||
"ffaf00": 214,
|
||||
"ffaf5f": 215,
|
||||
"ffaf87": 216,
|
||||
"ffafaf": 217,
|
||||
"ffafd7": 218,
|
||||
"ffafff": 219,
|
||||
"ffd700": 220,
|
||||
"ffd75f": 221,
|
||||
"ffd787": 222,
|
||||
"ffd7af": 223,
|
||||
"ffd7d7": 224,
|
||||
"ffd7ff": 225,
|
||||
// "ffff00": 226,
|
||||
"ffff01": 226, // up: avoid key conflicts, value + 1
|
||||
"ffff5f": 227,
|
||||
"ffff87": 228,
|
||||
"ffffaf": 229,
|
||||
"ffffd7": 230,
|
||||
// "ffffff": 231,
|
||||
"fffffe": 231, // up: avoid key conflicts, value - 1
|
||||
|
||||
// Gray-scale range.
|
||||
"080808": 232,
|
||||
"121212": 233,
|
||||
"1c1c1c": 234,
|
||||
"262626": 235,
|
||||
"303030": 236,
|
||||
"3a3a3a": 237,
|
||||
"444444": 238,
|
||||
"4e4e4e": 239,
|
||||
"585858": 240,
|
||||
"626262": 241,
|
||||
"6c6c6c": 242,
|
||||
"767676": 243,
|
||||
// "808080": 244,
|
||||
"808081": 244, // up: avoid key conflicts, value + 1
|
||||
"8a8a8a": 245,
|
||||
"949494": 246,
|
||||
"9e9e9e": 247,
|
||||
"a8a8a8": 248,
|
||||
"b2b2b2": 249,
|
||||
"bcbcbc": 250,
|
||||
"c6c6c6": 251,
|
||||
"d0d0d0": 252,
|
||||
"dadada": 253,
|
||||
"e4e4e4": 254,
|
||||
"eeeeee": 255,
|
||||
}
|
||||
|
||||
incs = []uint8{0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
|
||||
)
|
||||
|
||||
func initHex2basicMap() map[string]uint8 {
|
||||
h2b := make(map[string]uint8, len(basic2hexMap))
|
||||
// ini data map
|
||||
for u, s := range basic2hexMap {
|
||||
h2b[s] = u
|
||||
}
|
||||
return h2b
|
||||
}
|
||||
|
||||
func init256ToHexMap() map[uint8]string {
|
||||
c256toh := make(map[uint8]string, len(hexTo256Table))
|
||||
// ini data map
|
||||
for hex, c256 := range hexTo256Table {
|
||||
c256toh[c256] = hex
|
||||
}
|
||||
return c256toh
|
||||
}
|
||||
|
||||
// RgbTo256Table mapping data
|
||||
func RgbTo256Table() map[string]uint8 {
|
||||
return hexTo256Table
|
||||
}
|
||||
|
||||
// Colors2code convert colors to code. return like "32;45;3"
|
||||
func Colors2code(colors ...Color) string {
|
||||
if len(colors) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var codes []string
|
||||
for _, color := range colors {
|
||||
codes = append(codes, color.String())
|
||||
}
|
||||
|
||||
return strings.Join(codes, ";")
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* HEX code <=> RGB/True color code
|
||||
*************************************************************/
|
||||
|
||||
// Hex2rgb alias of the HexToRgb()
|
||||
func Hex2rgb(hex string) []int { return HexToRgb(hex) }
|
||||
|
||||
// HexToRGB alias of the HexToRgb()
|
||||
func HexToRGB(hex string) []int { return HexToRgb(hex) }
|
||||
|
||||
// HexToRgb convert hex color string to RGB numbers
|
||||
//
|
||||
// Usage:
|
||||
// rgb := HexToRgb("ccc") // rgb: [204 204 204]
|
||||
// rgb := HexToRgb("aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204]
|
||||
func HexToRgb(hex string) (rgb []int) {
|
||||
hex = strings.TrimSpace(hex)
|
||||
if hex == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// like from css. eg "#ccc" "#ad99c0"
|
||||
if hex[0] == '#' {
|
||||
hex = hex[1:]
|
||||
}
|
||||
|
||||
hex = strings.ToLower(hex)
|
||||
switch len(hex) {
|
||||
case 3: // "ccc"
|
||||
hex = string([]byte{hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]})
|
||||
case 8: // "0xad99c0"
|
||||
hex = strings.TrimPrefix(hex, "0x")
|
||||
}
|
||||
|
||||
// recheck
|
||||
if len(hex) != 6 {
|
||||
return
|
||||
}
|
||||
|
||||
// convert string to int64
|
||||
if i64, err := strconv.ParseInt(hex, 16, 32); err == nil {
|
||||
color := int(i64)
|
||||
// parse int
|
||||
rgb = make([]int, 3)
|
||||
rgb[0] = color >> 16
|
||||
rgb[1] = (color & 0x00FF00) >> 8
|
||||
rgb[2] = color & 0x0000FF
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Rgb2hex alias of the RgbToHex()
|
||||
func Rgb2hex(rgb []int) string { return RgbToHex(rgb) }
|
||||
|
||||
// RgbToHex convert RGB-code to hex-code
|
||||
//
|
||||
// Usage:
|
||||
// hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc"
|
||||
func RgbToHex(rgb []int) string {
|
||||
hexNodes := make([]string, len(rgb))
|
||||
|
||||
for _, v := range rgb {
|
||||
hexNodes = append(hexNodes, strconv.FormatInt(int64(v), 16))
|
||||
}
|
||||
return strings.Join(hexNodes, "")
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* 4bit(16) color <=> RGB/True color
|
||||
*************************************************************/
|
||||
|
||||
// Basic2hex convert basic color to hex string.
|
||||
func Basic2hex(val uint8) string {
|
||||
return basic2hexMap[val]
|
||||
}
|
||||
|
||||
// Hex2basic convert hex string to basic color code.
|
||||
func Hex2basic(hex string) uint8 {
|
||||
return hex2basicMap[hex]
|
||||
}
|
||||
|
||||
// Rgb2basic alias of the RgbToAnsi()
|
||||
func Rgb2basic(r, g, b uint8, isBg bool) uint8 {
|
||||
// is basic color, direct use static map data.
|
||||
hex := RgbToHex([]int{int(r), int(g), int(b)})
|
||||
if val, ok := hex2basicMap[hex]; ok {
|
||||
if isBg {
|
||||
return val + 10
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
return RgbToAnsi(r, g, b, isBg)
|
||||
}
|
||||
|
||||
// Rgb2ansi alias of the RgbToAnsi()
|
||||
func Rgb2ansi(r, g, b uint8, isBg bool) uint8 {
|
||||
return RgbToAnsi(r, g, b, isBg)
|
||||
}
|
||||
|
||||
// RgbToAnsi convert RGB-code to 16-code
|
||||
// refer https://github.com/radareorg/radare2/blob/master/libr/cons/rgb.c#L249-L271
|
||||
func RgbToAnsi(r, g, b uint8, isBg bool) uint8 {
|
||||
var bright, c, k uint8
|
||||
base := compareVal(isBg, BgBase, FgBase)
|
||||
|
||||
// eco bright-specific
|
||||
if r == 0x80 && g == 0x80 && b == 0x80 { // 0x80=128
|
||||
bright = 53
|
||||
} else if r == 0xff || g == 0xff || b == 0xff { // 0xff=255
|
||||
bright = 60
|
||||
} // else bright = 0
|
||||
|
||||
if r == g && g == b {
|
||||
// 0x7f=127
|
||||
// r = (r > 0x7f) ? 1 : 0;
|
||||
r = compareVal(r > 0x7f, 1, 0)
|
||||
g = compareVal(g > 0x7f, 1, 0)
|
||||
b = compareVal(b > 0x7f, 1, 0)
|
||||
} else {
|
||||
k = (r + g + b) / 3
|
||||
|
||||
// r = (r >= k) ? 1 : 0;
|
||||
r = compareVal(r >= k, 1, 0)
|
||||
g = compareVal(g >= k, 1, 0)
|
||||
b = compareVal(b >= k, 1, 0)
|
||||
}
|
||||
|
||||
// c = (r ? 1 : 0) + (g ? (b ? 6 : 2) : (b ? 4 : 0))
|
||||
c = compareVal(r > 0, 1, 0)
|
||||
|
||||
if g > 0 {
|
||||
c += compareVal(b > 0, 6, 2)
|
||||
} else {
|
||||
c += compareVal(b > 0, 4, 0)
|
||||
}
|
||||
return base + bright + c
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* 8bit(256) color <=> RGB/True color
|
||||
*************************************************************/
|
||||
|
||||
// Rgb2short convert RGB-code to 256-code
|
||||
func Rgb2short(r, g, b uint8) uint8 {
|
||||
return RgbTo256(r, g, b)
|
||||
}
|
||||
|
||||
// RgbTo256 convert RGB-code to 256-code
|
||||
func RgbTo256(r, g, b uint8) uint8 {
|
||||
res := make([]uint8, 3)
|
||||
for partI, part := range [3]uint8{r, g, b} {
|
||||
i := 0
|
||||
for i < len(incs)-1 {
|
||||
s, b := incs[i], incs[i+1] // smaller, bigger
|
||||
if s <= part && part <= b {
|
||||
s1 := math.Abs(float64(s) - float64(part))
|
||||
b1 := math.Abs(float64(b) - float64(part))
|
||||
var closest uint8
|
||||
if s1 < b1 {
|
||||
closest = s
|
||||
} else {
|
||||
closest = b
|
||||
}
|
||||
res[partI] = closest
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
hex := fmt.Sprintf("%02x%02x%02x", res[0], res[1], res[2])
|
||||
equiv := hexTo256Table[hex]
|
||||
return equiv
|
||||
}
|
||||
|
||||
// C256ToRgb convert an 256 color code to RGB numbers
|
||||
func C256ToRgb(val uint8) (rgb []uint8) {
|
||||
hex := c256ToHexMap[val]
|
||||
// convert to rgb code
|
||||
rgbInts := Hex2rgb(hex)
|
||||
|
||||
return []uint8{
|
||||
uint8(rgbInts[0]),
|
||||
uint8(rgbInts[1]),
|
||||
uint8(rgbInts[2]),
|
||||
}
|
||||
}
|
||||
|
||||
// C256ToRgbV1 convert an 256 color code to RGB numbers
|
||||
// refer https://github.com/torvalds/linux/commit/cec5b2a97a11ade56a701e83044d0a2a984c67b4
|
||||
func C256ToRgbV1(val uint8) (rgb []uint8) {
|
||||
var r, g, b uint8
|
||||
if val < 8 { // Standard colours.
|
||||
// r = val&1 ? 0xaa : 0x00;
|
||||
r = compareVal(val&1 == 1, 0xaa, 0x00)
|
||||
g = compareVal(val&2 == 2, 0xaa, 0x00)
|
||||
b = compareVal(val&4 == 4, 0xaa, 0x00)
|
||||
} else if val < 16 {
|
||||
// r = val & 1 ? 0xff : 0x55;
|
||||
r = compareVal(val&1 == 1, 0xff, 0x55)
|
||||
g = compareVal(val&2 == 2, 0xff, 0x55)
|
||||
b = compareVal(val&4 == 4, 0xff, 0x55)
|
||||
} else if val < 232 { /* 6x6x6 colour cube. */
|
||||
r = (val - 16) / 36 * 85 / 2
|
||||
g = (val - 16) / 6 % 6 * 85 / 2
|
||||
b = (val - 16) % 6 * 85 / 2
|
||||
} else { /* Grayscale ramp. */
|
||||
nv := uint8(int(val)*10 - 2312)
|
||||
// set value
|
||||
r, g, b = nv, nv, nv
|
||||
}
|
||||
|
||||
return []uint8{r, g, b}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* helper methods for detect color supports
|
||||
*************************************************************/
|
||||
|
||||
// DetectColorLevel for current env
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func DetectColorLevel() terminfo.ColorLevel {
|
||||
level, _ := detectTermColorLevel()
|
||||
return level
|
||||
}
|
||||
|
||||
// detect terminal color support level
|
||||
//
|
||||
// refer https://github.com/Delta456/box-cli-maker
|
||||
func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
|
||||
// on windows WSL:
|
||||
// - runtime.GOOS == "Linux"
|
||||
// - support true-color
|
||||
// env:
|
||||
// WSL_DISTRO_NAME=Debian
|
||||
if val := os.Getenv("WSL_DISTRO_NAME"); val != "" {
|
||||
// detect WSL as it has True Color support
|
||||
if detectWSL() {
|
||||
debugf("True Color support on WSL environment")
|
||||
return terminfo.ColorLevelMillions, false
|
||||
}
|
||||
}
|
||||
|
||||
isWin := runtime.GOOS == "windows"
|
||||
termVal := os.Getenv("TERM")
|
||||
|
||||
// on TERM=screen: not support true-color
|
||||
if termVal != "screen" {
|
||||
// On JetBrains Terminal
|
||||
// - support true-color
|
||||
// env:
|
||||
// TERMINAL_EMULATOR=JetBrains-JediTerm
|
||||
val := os.Getenv("TERMINAL_EMULATOR")
|
||||
if val == "JetBrains-JediTerm" {
|
||||
debugf("True Color support on JetBrains-JediTerm, is win: %v", isWin)
|
||||
return terminfo.ColorLevelMillions, isWin
|
||||
}
|
||||
}
|
||||
|
||||
// level, err = terminfo.ColorLevelFromEnv()
|
||||
level = detectColorLevelFromEnv(termVal, isWin)
|
||||
debugf("color level by detectColorLevelFromEnv: %s", level.String())
|
||||
|
||||
// fallback: simple detect by TERM value string.
|
||||
if level == terminfo.ColorLevelNone {
|
||||
debugf("level none - fallback check special term color support")
|
||||
// on Windows: enable VTP as it has True Color support
|
||||
level, needVTP = detectSpecialTermColor(termVal)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// detectColorFromEnv returns the color level COLORTERM, FORCE_COLOR,
|
||||
// TERM_PROGRAM, or determined from the TERM environment variable.
|
||||
//
|
||||
// refer the terminfo.ColorLevelFromEnv()
|
||||
// https://en.wikipedia.org/wiki/Terminfo
|
||||
func detectColorLevelFromEnv(termVal string, isWin bool) terminfo.ColorLevel {
|
||||
// check for overriding environment variables
|
||||
colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
|
||||
switch {
|
||||
case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit"):
|
||||
if termVal == "screen" { // on TERM=screen: not support true-color
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
return terminfo.ColorLevelMillions
|
||||
case colorTerm != "" || forceColor != "":
|
||||
return terminfo.ColorLevelBasic
|
||||
case termProg == "Apple_Terminal":
|
||||
return terminfo.ColorLevelHundreds
|
||||
case termProg == "Terminus" || termProg == "Hyper":
|
||||
if termVal == "screen" { // on TERM=screen: not support true-color
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
return terminfo.ColorLevelMillions
|
||||
case termProg == "iTerm.app":
|
||||
if termVal == "screen" { // on TERM=screen: not support true-color
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
|
||||
// check iTerm version
|
||||
ver := os.Getenv("TERM_PROGRAM_VERSION")
|
||||
if ver != "" {
|
||||
i, err := strconv.Atoi(strings.Split(ver, ".")[0])
|
||||
if err != nil {
|
||||
saveInternalError(terminfo.ErrInvalidTermProgramVersion)
|
||||
// return terminfo.ColorLevelNone
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
if i == 3 {
|
||||
return terminfo.ColorLevelMillions
|
||||
}
|
||||
}
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
|
||||
// otherwise determine from TERM's max_colors capability
|
||||
if !isWin && termVal != "" {
|
||||
debugf("TERM=%s - check color level by load terminfo file", termVal)
|
||||
ti, err := terminfo.Load(termVal)
|
||||
if err != nil {
|
||||
saveInternalError(err)
|
||||
return terminfo.ColorLevelNone
|
||||
}
|
||||
|
||||
debugf("the loaded term info file is: %s", ti.File)
|
||||
v, ok := ti.Nums[terminfo.MaxColors]
|
||||
switch {
|
||||
case !ok || v <= 16:
|
||||
return terminfo.ColorLevelNone
|
||||
case ok && v >= 256:
|
||||
return terminfo.ColorLevelHundreds
|
||||
}
|
||||
return terminfo.ColorLevelBasic
|
||||
}
|
||||
|
||||
// no TERM env value. default return none level
|
||||
return terminfo.ColorLevelNone
|
||||
// return terminfo.ColorLevelBasic
|
||||
}
|
||||
|
||||
var detectedWSL bool
|
||||
var wslContents string
|
||||
|
||||
// https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
|
||||
func detectWSL() bool {
|
||||
if !detectedWSL {
|
||||
b := make([]byte, 1024)
|
||||
// `cat /proc/version`
|
||||
// on mac:
|
||||
// !not the file!
|
||||
// on linux(debian,ubuntu,alpine):
|
||||
// Linux version 4.19.121-linuxkit (root@18b3f92ade35) (gcc version 9.2.0 (Alpine 9.2.0)) #1 SMP Thu Jan 21 15:36:34 UTC 2021
|
||||
// on win git bash, conEmu:
|
||||
// MINGW64_NT-10.0-19042 version 3.1.7-340.x86_64 (@WIN-N0G619FD3UK) (gcc version 9.3.0 (GCC) ) 2020-10-23 13:08 UTC
|
||||
// on WSL:
|
||||
// Linux version 4.4.0-19041-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #488-Microsoft Mon Sep 01 13:43:00 PST 2020
|
||||
f, err := os.Open("/proc/version")
|
||||
if err == nil {
|
||||
_, _ = f.Read(b) // ignore error
|
||||
if err = f.Close(); err != nil {
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
wslContents = string(b)
|
||||
}
|
||||
detectedWSL = true
|
||||
}
|
||||
return strings.Contains(wslContents, "Microsoft")
|
||||
}
|
||||
|
||||
// refer
|
||||
// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_unix.go#L27-L45
|
||||
// detect WSL as it has True Color support
|
||||
func isWSL() bool {
|
||||
// on windows WSL:
|
||||
// - runtime.GOOS == "Linux"
|
||||
// - support true-color
|
||||
// WSL_DISTRO_NAME=Debian
|
||||
if val := os.Getenv("WSL_DISTRO_NAME"); val == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// `cat /proc/sys/kernel/osrelease`
|
||||
// on mac:
|
||||
// !not the file!
|
||||
// on linux:
|
||||
// 4.19.121-linuxkit
|
||||
// on WSL Output:
|
||||
// 4.4.0-19041-Microsoft
|
||||
wsl, err := ioutil.ReadFile("/proc/sys/kernel/osrelease")
|
||||
if err != nil {
|
||||
saveInternalError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
// it gives "Microsoft" for WSL and "microsoft" for WSL 2
|
||||
// it support True-color
|
||||
content := strings.ToLower(string(wsl))
|
||||
return strings.Contains(content, "microsoft")
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* helper methods for check env
|
||||
*************************************************************/
|
||||
|
||||
// IsWindows OS env
|
||||
func IsWindows() bool {
|
||||
return runtime.GOOS == "windows"
|
||||
}
|
||||
|
||||
// IsConsole Determine whether w is one of stderr, stdout, stdin
|
||||
func IsConsole(w io.Writer) bool {
|
||||
o, ok := w.(*os.File)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
fd := o.Fd()
|
||||
|
||||
// fix: cannot use 'o == os.Stdout' to compare
|
||||
return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
|
||||
}
|
||||
|
||||
// IsMSys msys(MINGW64) environment, does not necessarily support color
|
||||
func IsMSys() bool {
|
||||
// like "MSYSTEM=MINGW64"
|
||||
if len(os.Getenv("MSYSTEM")) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSupportColor check current console is support color.
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func IsSupportColor() bool {
|
||||
return IsSupport16Color()
|
||||
}
|
||||
|
||||
// IsSupportColor check current console is support color.
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func IsSupport16Color() bool {
|
||||
level, _ := detectTermColorLevel()
|
||||
return level > terminfo.ColorLevelNone
|
||||
}
|
||||
|
||||
// IsSupport256Color render check
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func IsSupport256Color() bool {
|
||||
level, _ := detectTermColorLevel()
|
||||
return level > terminfo.ColorLevelBasic
|
||||
}
|
||||
|
||||
// IsSupportRGBColor check. alias of the IsSupportTrueColor()
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func IsSupportRGBColor() bool {
|
||||
return IsSupportTrueColor()
|
||||
}
|
||||
|
||||
// IsSupportTrueColor render check.
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
//
|
||||
// ENV:
|
||||
// "COLORTERM=truecolor"
|
||||
// "COLORTERM=24bit"
|
||||
func IsSupportTrueColor() bool {
|
||||
level, _ := detectTermColorLevel()
|
||||
return level > terminfo.ColorLevelHundreds
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// +build !windows
|
||||
|
||||
// The method in the file has no effect
|
||||
// Only for compatibility with non-Windows systems
|
||||
|
||||
package color
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
// detect special term color support
|
||||
func detectSpecialTermColor(termVal string) (terminfo.ColorLevel, bool) {
|
||||
if termVal == "" {
|
||||
return terminfo.ColorLevelNone, false
|
||||
}
|
||||
|
||||
debugf("terminfo check fail - fallback detect color by check TERM value")
|
||||
|
||||
// on TERM=screen:
|
||||
// - support 256, not support true-color. test on macOS
|
||||
if termVal == "screen" {
|
||||
return terminfo.ColorLevelHundreds, false
|
||||
}
|
||||
|
||||
if strings.Contains(termVal, "256color") {
|
||||
return terminfo.ColorLevelHundreds, false
|
||||
}
|
||||
|
||||
if strings.Contains(termVal, "xterm") {
|
||||
return terminfo.ColorLevelHundreds, false
|
||||
// return terminfo.ColorLevelBasic, false
|
||||
}
|
||||
|
||||
// return terminfo.ColorLevelNone, nil
|
||||
return terminfo.ColorLevelBasic, false
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
//
|
||||
// Usage:
|
||||
// IsTerminal(os.Stdout.Fd())
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
// +build windows
|
||||
|
||||
// Display color on windows
|
||||
// refer:
|
||||
// golang.org/x/sys/windows
|
||||
// golang.org/x/crypto/ssh/terminal
|
||||
// https://docs.microsoft.com/en-us/windows/console
|
||||
package color
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// related docs
|
||||
// https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences
|
||||
// https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples
|
||||
var (
|
||||
// isMSys bool
|
||||
kernel32 *syscall.LazyDLL
|
||||
|
||||
procGetConsoleMode *syscall.LazyProc
|
||||
procSetConsoleMode *syscall.LazyProc
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !SupportColor() {
|
||||
isLikeInCmd = true
|
||||
return
|
||||
}
|
||||
|
||||
// if disabled.
|
||||
if !Enable {
|
||||
return
|
||||
}
|
||||
|
||||
// if at windows's ConEmu, Cmder, putty ... terminals not need VTP
|
||||
|
||||
// -------- try force enable colors on windows terminal -------
|
||||
tryEnableVTP(needVTP)
|
||||
|
||||
// fetch console screen buffer info
|
||||
// err := getConsoleScreenBufferInfo(uintptr(syscall.Stdout), &defScreenInfo)
|
||||
}
|
||||
|
||||
// try force enable colors on windows terminal
|
||||
func tryEnableVTP(enable bool) bool {
|
||||
if !enable {
|
||||
return false
|
||||
}
|
||||
|
||||
debugf("True-Color by enable VirtualTerminalProcessing on windows")
|
||||
|
||||
initKernel32Proc()
|
||||
|
||||
// enable colors on windows terminal
|
||||
if tryEnableOnCONOUT() {
|
||||
return true
|
||||
}
|
||||
|
||||
return tryEnableOnStdout()
|
||||
}
|
||||
|
||||
func initKernel32Proc() {
|
||||
if kernel32 != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// load related windows dll
|
||||
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||
}
|
||||
|
||||
func tryEnableOnCONOUT() bool {
|
||||
outHandle, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
|
||||
if err != nil {
|
||||
saveInternalError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
err = EnableVirtualTerminalProcessing(outHandle, true)
|
||||
if err != nil {
|
||||
saveInternalError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func tryEnableOnStdout() bool {
|
||||
// try direct open syscall.Stdout
|
||||
err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||
if err != nil {
|
||||
saveInternalError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Get the Windows Version and Build Number
|
||||
var (
|
||||
winVersion, _, buildNumber = windows.RtlGetNtVersionNumbers()
|
||||
)
|
||||
|
||||
// refer
|
||||
// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57
|
||||
// https://github.com/gookit/color/issues/25#issuecomment-738727917
|
||||
// detects the Color Level Supported on windows: cmd, powerShell
|
||||
func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP bool) {
|
||||
if os.Getenv("ConEmuANSI") == "ON" {
|
||||
debugf("support True Color by ConEmuANSI=ON")
|
||||
// ConEmuANSI is "ON" for generic ANSI support
|
||||
// but True Color option is enabled by default
|
||||
// I am just assuming that people wouldn't have disabled it
|
||||
// Even if it is not enabled then ConEmu will auto round off
|
||||
// accordingly
|
||||
return terminfo.ColorLevelMillions, false
|
||||
}
|
||||
|
||||
// Before Windows 10 Build Number 10586, console never supported ANSI Colors
|
||||
if buildNumber < 10586 || winVersion < 10 {
|
||||
// Detect if using ANSICON on older systems
|
||||
if os.Getenv("ANSICON") != "" {
|
||||
conVersion := os.Getenv("ANSICON_VER")
|
||||
// 8 bit Colors were only supported after v1.81 release
|
||||
if conVersion >= "181" {
|
||||
return terminfo.ColorLevelHundreds, false
|
||||
}
|
||||
return terminfo.ColorLevelBasic, false
|
||||
}
|
||||
|
||||
return terminfo.ColorLevelNone, false
|
||||
}
|
||||
|
||||
// True Color is not available before build 14931 so fallback to 8 bit color.
|
||||
if buildNumber < 14931 {
|
||||
return terminfo.ColorLevelHundreds, true
|
||||
}
|
||||
|
||||
// Windows 10 build 14931 is the first release that supports 16m/TrueColor
|
||||
debugf("support True Color on windows version is >= build 14931")
|
||||
return terminfo.ColorLevelMillions, true
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* render full color code on windows(8,16,24bit color)
|
||||
*************************************************************/
|
||||
|
||||
// docs https://docs.microsoft.com/zh-cn/windows/console/getconsolemode#parameters
|
||||
const (
|
||||
// equals to docs page's ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
EnableVirtualTerminalProcessingMode uint32 = 0x4
|
||||
)
|
||||
|
||||
// EnableVirtualTerminalProcessing Enable virtual terminal processing
|
||||
//
|
||||
// ref from github.com/konsorten/go-windows-terminal-sequences
|
||||
// doc https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples
|
||||
//
|
||||
// Usage:
|
||||
// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||
// // support print color text
|
||||
// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
|
||||
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
||||
var mode uint32
|
||||
// Check if it is currently in the terminal
|
||||
// err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
||||
err := syscall.GetConsoleMode(stream, &mode)
|
||||
if err != nil {
|
||||
// fmt.Println("EnableVirtualTerminalProcessing", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if enable {
|
||||
mode |= EnableVirtualTerminalProcessingMode
|
||||
} else {
|
||||
mode &^= EnableVirtualTerminalProcessingMode
|
||||
}
|
||||
|
||||
ret, _, err := procSetConsoleMode.Call(uintptr(stream), uintptr(mode))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderColorCodeOnCmd enable cmd color render.
|
||||
// func renderColorCodeOnCmd(fn func()) {
|
||||
// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||
// // if is not in terminal, will clear color tag.
|
||||
// if err != nil {
|
||||
// // panic(err)
|
||||
// fn()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // force open color render
|
||||
// old := ForceOpenColor()
|
||||
// fn()
|
||||
// // revert color setting
|
||||
// supportColor = old
|
||||
//
|
||||
// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
/*************************************************************
|
||||
* render simple color code on windows
|
||||
*************************************************************/
|
||||
|
||||
// IsTty returns true if the given file descriptor is a terminal.
|
||||
func IsTty(fd uintptr) bool {
|
||||
initKernel32Proc()
|
||||
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
//
|
||||
// Usage:
|
||||
// fd := os.Stdout.Fd()
|
||||
// fd := uintptr(syscall.Stdout) // for windows
|
||||
// IsTerminal(fd)
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
initKernel32Proc()
|
||||
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
module github.com/gookit/color
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,122 @@
|
|||
package color
|
||||
|
||||
import "fmt"
|
||||
|
||||
/*************************************************************
|
||||
* colored message Printer
|
||||
*************************************************************/
|
||||
|
||||
// PrinterFace interface
|
||||
type PrinterFace interface {
|
||||
fmt.Stringer
|
||||
Sprint(a ...interface{}) string
|
||||
Sprintf(format string, a ...interface{}) string
|
||||
Print(a ...interface{})
|
||||
Printf(format string, a ...interface{})
|
||||
Println(a ...interface{})
|
||||
}
|
||||
|
||||
// Printer a generic color message printer.
|
||||
//
|
||||
// Usage:
|
||||
// p := &Printer{Code: "32;45;3"}
|
||||
// p.Print("message")
|
||||
type Printer struct {
|
||||
// NoColor disable color.
|
||||
NoColor bool
|
||||
// Code color code string. eg "32;45;3"
|
||||
Code string
|
||||
}
|
||||
|
||||
// NewPrinter instance
|
||||
func NewPrinter(colorCode string) *Printer {
|
||||
return &Printer{Code: colorCode}
|
||||
}
|
||||
|
||||
// String returns color code string. eg: "32;45;3"
|
||||
func (p *Printer) String() string {
|
||||
// panic("implement me")
|
||||
return p.Code
|
||||
}
|
||||
|
||||
// Sprint returns rendering colored messages
|
||||
func (p *Printer) Sprint(a ...interface{}) string {
|
||||
return RenderCode(p.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendering colored messages
|
||||
func (p *Printer) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(p.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Print rendering colored messages
|
||||
func (p *Printer) Print(a ...interface{}) {
|
||||
doPrintV2(p.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and rendering colored messages
|
||||
func (p *Printer) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(p.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println rendering colored messages with newline
|
||||
func (p *Printer) Println(a ...interface{}) {
|
||||
doPrintlnV2(p.Code, a)
|
||||
}
|
||||
|
||||
// IsEmpty color code
|
||||
func (p *Printer) IsEmpty() bool {
|
||||
return p.Code == ""
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* SimplePrinter struct
|
||||
*************************************************************/
|
||||
|
||||
// SimplePrinter use for quick use color print on inject to struct
|
||||
type SimplePrinter struct{}
|
||||
|
||||
// Print message
|
||||
func (s *SimplePrinter) Print(v ...interface{}) {
|
||||
Print(v...)
|
||||
}
|
||||
|
||||
// Printf message
|
||||
func (s *SimplePrinter) Printf(format string, v ...interface{}) {
|
||||
Printf(format, v...)
|
||||
}
|
||||
|
||||
// Println message
|
||||
func (s *SimplePrinter) Println(v ...interface{}) {
|
||||
Println(v...)
|
||||
}
|
||||
|
||||
// Infof message
|
||||
func (s *SimplePrinter) Infof(format string, a ...interface{}) {
|
||||
Info.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Infoln message
|
||||
func (s *SimplePrinter) Infoln(a ...interface{}) {
|
||||
Info.Println(a...)
|
||||
}
|
||||
|
||||
// Warnf message
|
||||
func (s *SimplePrinter) Warnf(format string, a ...interface{}) {
|
||||
Warn.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Warnln message
|
||||
func (s *SimplePrinter) Warnln(a ...interface{}) {
|
||||
Warn.Println(a...)
|
||||
}
|
||||
|
||||
// Errorf message
|
||||
func (s *SimplePrinter) Errorf(format string, a ...interface{}) {
|
||||
Error.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Errorln message
|
||||
func (s *SimplePrinter) Errorln(a ...interface{}) {
|
||||
Error.Println(a...)
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package color
|
||||
|
||||
/*************************************************************
|
||||
* quick use color print message
|
||||
*************************************************************/
|
||||
|
||||
// Redp print message with Red color
|
||||
func Redp(a ...interface{}) {
|
||||
Red.Print(a...)
|
||||
}
|
||||
|
||||
// Redln print message line with Red color
|
||||
func Redln(a ...interface{}) {
|
||||
Red.Println(a...)
|
||||
}
|
||||
|
||||
// Bluep print message with Blue color
|
||||
func Bluep(a ...interface{}) {
|
||||
Blue.Print(a...)
|
||||
}
|
||||
|
||||
// Blueln print message line with Blue color
|
||||
func Blueln(a ...interface{}) {
|
||||
Blue.Println(a...)
|
||||
}
|
||||
|
||||
// Cyanp print message with Cyan color
|
||||
func Cyanp(a ...interface{}) {
|
||||
Cyan.Print(a...)
|
||||
}
|
||||
|
||||
// Cyanln print message line with Cyan color
|
||||
func Cyanln(a ...interface{}) {
|
||||
Cyan.Println(a...)
|
||||
}
|
||||
|
||||
// Grayp print message with Gray color
|
||||
func Grayp(a ...interface{}) {
|
||||
Gray.Print(a...)
|
||||
}
|
||||
|
||||
// Grayln print message line with Gray color
|
||||
func Grayln(a ...interface{}) {
|
||||
Gray.Println(a...)
|
||||
}
|
||||
|
||||
// Greenp print message with Green color
|
||||
func Greenp(a ...interface{}) {
|
||||
Green.Print(a...)
|
||||
}
|
||||
|
||||
// Greenln print message line with Green color
|
||||
func Greenln(a ...interface{}) {
|
||||
Green.Println(a...)
|
||||
}
|
||||
|
||||
// Yellowp print message with Yellow color
|
||||
func Yellowp(a ...interface{}) {
|
||||
Yellow.Print(a...)
|
||||
}
|
||||
|
||||
// Yellowln print message line with Yellow color
|
||||
func Yellowln(a ...interface{}) {
|
||||
Yellow.Println(a...)
|
||||
}
|
||||
|
||||
// Magentap print message with Magenta color
|
||||
func Magentap(a ...interface{}) {
|
||||
Magenta.Print(a...)
|
||||
}
|
||||
|
||||
// Magentaln print message line with Magenta color
|
||||
func Magentaln(a ...interface{}) {
|
||||
Magenta.Println(a...)
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* quick use style print message
|
||||
*************************************************************/
|
||||
|
||||
// Infof print message with Info style
|
||||
func Infof(format string, a ...interface{}) {
|
||||
Info.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Infoln print message with Info style
|
||||
func Infoln(a ...interface{}) {
|
||||
Info.Println(a...)
|
||||
}
|
||||
|
||||
// Errorf print message with Error style
|
||||
func Errorf(format string, a ...interface{}) {
|
||||
Error.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Errorln print message with Error style
|
||||
func Errorln(a ...interface{}) {
|
||||
Error.Println(a...)
|
||||
}
|
||||
|
||||
// Warnf print message with Warn style
|
||||
func Warnf(format string, a ...interface{}) {
|
||||
Warn.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Warnln print message with Warn style
|
||||
func Warnln(a ...interface{}) {
|
||||
Warn.Println(a...)
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* 16 color Style
|
||||
*************************************************************/
|
||||
|
||||
// Style a 16 color style. can add: fg color, bg color, color options
|
||||
//
|
||||
// Example:
|
||||
// color.Style{color.FgGreen}.Print("message")
|
||||
type Style []Color
|
||||
|
||||
// New create a custom style
|
||||
//
|
||||
// Usage:
|
||||
// color.New(color.FgGreen).Print("message")
|
||||
// equals to:
|
||||
// color.Style{color.FgGreen}.Print("message")
|
||||
func New(colors ...Color) Style {
|
||||
return colors
|
||||
}
|
||||
|
||||
// Save to global styles map
|
||||
func (s Style) Save(name string) {
|
||||
AddStyle(name, s)
|
||||
}
|
||||
|
||||
// Add to global styles map
|
||||
func (s *Style) Add(cs ...Color) {
|
||||
*s = append(*s, cs...)
|
||||
}
|
||||
|
||||
// Render render text
|
||||
// Usage:
|
||||
// color.New(color.FgGreen).Render("text")
|
||||
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
|
||||
func (s Style) Render(a ...interface{}) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Renderln render text line.
|
||||
// like Println, will add spaces for each argument
|
||||
// Usage:
|
||||
// color.New(color.FgGreen).Renderln("text", "more")
|
||||
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more")
|
||||
func (s Style) Renderln(a ...interface{}) string {
|
||||
return RenderWithSpaces(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprint is alias of the 'Render'
|
||||
func (s Style) Sprint(a ...interface{}) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf format and render message.
|
||||
func (s Style) Sprintf(format string, a ...interface{}) string {
|
||||
return RenderString(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Print render and Print text
|
||||
func (s Style) Print(a ...interface{}) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf render and print text
|
||||
func (s Style) Printf(format string, a ...interface{}) {
|
||||
doPrintV2(s.Code(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println render and print text line
|
||||
func (s Style) Println(a ...interface{}) {
|
||||
doPrintlnV2(s.String(), a)
|
||||
}
|
||||
|
||||
// Code convert to code string. returns like "32;45;3"
|
||||
func (s Style) Code() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// String convert to code string. returns like "32;45;3"
|
||||
func (s Style) String() string {
|
||||
return Colors2code(s...)
|
||||
}
|
||||
|
||||
// IsEmpty style
|
||||
func (s Style) IsEmpty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Theme(extended Style)
|
||||
*************************************************************/
|
||||
|
||||
// Theme definition. extends from Style
|
||||
type Theme struct {
|
||||
// Name theme name
|
||||
Name string
|
||||
// Style for the theme
|
||||
Style
|
||||
}
|
||||
|
||||
// NewTheme instance
|
||||
func NewTheme(name string, style Style) *Theme {
|
||||
return &Theme{name, style}
|
||||
}
|
||||
|
||||
// Save to themes map
|
||||
func (t *Theme) Save() {
|
||||
AddTheme(t.Name, t.Style)
|
||||
}
|
||||
|
||||
// Tips use name as title, only apply style for name
|
||||
func (t *Theme) Tips(format string, a ...interface{}) {
|
||||
// only apply style for name
|
||||
t.Print(strings.ToUpper(t.Name) + ": ")
|
||||
Printf(format+"\n", a...)
|
||||
}
|
||||
|
||||
// Prompt use name as title, and apply style for message
|
||||
func (t *Theme) Prompt(format string, a ...interface{}) {
|
||||
title := strings.ToUpper(t.Name) + ":"
|
||||
t.Println(title, fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Block like Prompt, but will wrap a empty line
|
||||
func (t *Theme) Block(format string, a ...interface{}) {
|
||||
title := strings.ToUpper(t.Name) + ":\n"
|
||||
|
||||
t.Println(title, fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Theme: internal themes
|
||||
*************************************************************/
|
||||
|
||||
// internal themes(like bootstrap style)
|
||||
// Usage:
|
||||
// color.Info.Print("message")
|
||||
// color.Info.Printf("a %s message", "test")
|
||||
// color.Warn.Println("message")
|
||||
// color.Error.Println("message")
|
||||
var (
|
||||
// Info color style
|
||||
Info = &Theme{"info", Style{OpReset, FgGreen}}
|
||||
// Note color style
|
||||
Note = &Theme{"note", Style{OpBold, FgLightCyan}}
|
||||
// Warn color style
|
||||
Warn = &Theme{"warning", Style{OpBold, FgYellow}}
|
||||
// Light color style
|
||||
Light = &Theme{"light", Style{FgLightWhite, BgBlack}}
|
||||
// Error color style
|
||||
Error = &Theme{"error", Style{FgLightWhite, BgRed}}
|
||||
// Danger color style
|
||||
Danger = &Theme{"danger", Style{OpBold, FgRed}}
|
||||
// Debug color style
|
||||
Debug = &Theme{"debug", Style{OpReset, FgCyan}}
|
||||
// Notice color style
|
||||
Notice = &Theme{"notice", Style{OpBold, FgCyan}}
|
||||
// Comment color style
|
||||
Comment = &Theme{"comment", Style{OpReset, FgYellow}}
|
||||
// Success color style
|
||||
Success = &Theme{"success", Style{OpBold, FgGreen}}
|
||||
// Primary color style
|
||||
Primary = &Theme{"primary", Style{OpReset, FgBlue}}
|
||||
// Question color style
|
||||
Question = &Theme{"question", Style{OpReset, FgMagenta}}
|
||||
// Secondary color style
|
||||
Secondary = &Theme{"secondary", Style{FgDarkGray}}
|
||||
)
|
||||
|
||||
// Themes internal defined themes.
|
||||
// Usage:
|
||||
// color.Themes["info"].Println("message")
|
||||
var Themes = map[string]*Theme{
|
||||
"info": Info,
|
||||
"note": Note,
|
||||
"light": Light,
|
||||
"error": Error,
|
||||
|
||||
"debug": Debug,
|
||||
"danger": Danger,
|
||||
"notice": Notice,
|
||||
"success": Success,
|
||||
"comment": Comment,
|
||||
"primary": Primary,
|
||||
"warning": Warn,
|
||||
|
||||
"question": Question,
|
||||
"secondary": Secondary,
|
||||
}
|
||||
|
||||
// AddTheme add a theme and style
|
||||
func AddTheme(name string, style Style) {
|
||||
Themes[name] = NewTheme(name, style)
|
||||
Styles[name] = style
|
||||
}
|
||||
|
||||
// GetTheme get defined theme by name
|
||||
func GetTheme(name string) *Theme {
|
||||
return Themes[name]
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* internal styles
|
||||
*************************************************************/
|
||||
|
||||
// Styles internal defined styles, like bootstrap styles.
|
||||
// Usage:
|
||||
// color.Styles["info"].Println("message")
|
||||
var Styles = map[string]Style{
|
||||
"info": {OpReset, FgGreen},
|
||||
"note": {OpBold, FgLightCyan},
|
||||
"light": {FgLightWhite, BgRed},
|
||||
"error": {FgLightWhite, BgRed},
|
||||
|
||||
"danger": {OpBold, FgRed},
|
||||
"notice": {OpBold, FgCyan},
|
||||
"success": {OpBold, FgGreen},
|
||||
"comment": {OpReset, FgMagenta},
|
||||
"primary": {OpReset, FgBlue},
|
||||
"warning": {OpBold, FgYellow},
|
||||
|
||||
"question": {OpReset, FgMagenta},
|
||||
"secondary": {FgDarkGray},
|
||||
}
|
||||
|
||||
// some style name alias
|
||||
var styleAliases = map[string]string{
|
||||
"err": "error",
|
||||
"suc": "success",
|
||||
"warn": "warning",
|
||||
}
|
||||
|
||||
// AddStyle add a style
|
||||
func AddStyle(name string, s Style) {
|
||||
Styles[name] = s
|
||||
}
|
||||
|
||||
// GetStyle get defined style by name
|
||||
func GetStyle(name string) Style {
|
||||
if s, ok := Styles[name]; ok {
|
||||
return s
|
||||
}
|
||||
|
||||
if realName, ok := styleAliases[name]; ok {
|
||||
return Styles[realName]
|
||||
}
|
||||
|
||||
// empty style
|
||||
return New()
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* color scheme
|
||||
*************************************************************/
|
||||
|
||||
// Scheme struct
|
||||
type Scheme struct {
|
||||
Name string
|
||||
Styles map[string]Style
|
||||
}
|
||||
|
||||
// NewScheme create new Scheme
|
||||
func NewScheme(name string, styles map[string]Style) *Scheme {
|
||||
return &Scheme{Name: name, Styles: styles}
|
||||
}
|
||||
|
||||
// NewDefaultScheme create an defuault color Scheme
|
||||
func NewDefaultScheme(name string) *Scheme {
|
||||
return NewScheme(name, map[string]Style{
|
||||
"info": {OpReset, FgGreen},
|
||||
"warn": {OpBold, FgYellow},
|
||||
"error": {FgLightWhite, BgRed},
|
||||
})
|
||||
}
|
||||
|
||||
// Style get by name
|
||||
func (s *Scheme) Style(name string) Style {
|
||||
return s.Styles[name]
|
||||
}
|
||||
|
||||
// Infof message print
|
||||
func (s *Scheme) Infof(format string, a ...interface{}) {
|
||||
s.Styles["info"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Infoln message print
|
||||
func (s *Scheme) Infoln(v ...interface{}) {
|
||||
s.Styles["info"].Println(v...)
|
||||
}
|
||||
|
||||
// Warnf message print
|
||||
func (s *Scheme) Warnf(format string, a ...interface{}) {
|
||||
s.Styles["warn"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Warnln message print
|
||||
func (s *Scheme) Warnln(v ...interface{}) {
|
||||
s.Styles["warn"].Println(v...)
|
||||
}
|
||||
|
||||
// Errorf message print
|
||||
func (s *Scheme) Errorf(format string, a ...interface{}) {
|
||||
s.Styles["error"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Errorln message print
|
||||
func (s *Scheme) Errorln(v ...interface{}) {
|
||||
s.Styles["error"].Println(v...)
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetTerminal by given code.
|
||||
func SetTerminal(code string) error {
|
||||
if !Enable || !SupportColor() {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := fmt.Fprintf(output, SettingTpl, code)
|
||||
return err
|
||||
}
|
||||
|
||||
// ResetTerminal terminal setting.
|
||||
func ResetTerminal() error {
|
||||
if !Enable || !SupportColor() {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := fmt.Fprint(output, ResetSet)
|
||||
return err
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* print methods(will auto parse color tags)
|
||||
*************************************************************/
|
||||
|
||||
// Print render color tag and print messages
|
||||
func Print(a ...interface{}) {
|
||||
Fprint(output, a...)
|
||||
}
|
||||
|
||||
// Printf format and print messages
|
||||
func Printf(format string, a ...interface{}) {
|
||||
Fprintf(output, format, a...)
|
||||
}
|
||||
|
||||
// Println messages with new line
|
||||
func Println(a ...interface{}) {
|
||||
Fprintln(output, a...)
|
||||
}
|
||||
|
||||
// Fprint print rendered messages to writer
|
||||
// Notice: will ignore print error
|
||||
func Fprint(w io.Writer, a ...interface{}) {
|
||||
_, err := fmt.Fprint(w, Render(a...))
|
||||
saveInternalError(err)
|
||||
|
||||
// if isLikeInCmd {
|
||||
// renderColorCodeOnCmd(func() {
|
||||
// _, _ = fmt.Fprint(w, Render(a...))
|
||||
// })
|
||||
// } else {
|
||||
// _, _ = fmt.Fprint(w, Render(a...))
|
||||
// }
|
||||
}
|
||||
|
||||
// Fprintf print format and rendered messages to writer.
|
||||
// Notice: will ignore print error
|
||||
func Fprintf(w io.Writer, format string, a ...interface{}) {
|
||||
str := fmt.Sprintf(format, a...)
|
||||
_, err := fmt.Fprint(w, ReplaceTag(str))
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
// Fprintln print rendered messages line to writer
|
||||
// Notice: will ignore print error
|
||||
func Fprintln(w io.Writer, a ...interface{}) {
|
||||
str := formatArgsForPrintln(a)
|
||||
_, err := fmt.Fprintln(w, ReplaceTag(str))
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
// Lprint passes colored messages to a log.Logger for printing.
|
||||
// Notice: should be goroutine safe
|
||||
func Lprint(l *log.Logger, a ...interface{}) {
|
||||
l.Print(Render(a...))
|
||||
}
|
||||
|
||||
// Render parse color tags, return rendered string.
|
||||
// Usage:
|
||||
// text := Render("<info>hello</> <cyan>world</>!")
|
||||
// fmt.Println(text)
|
||||
func Render(a ...interface{}) string {
|
||||
if len(a) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return ReplaceTag(fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Sprint parse color tags, return rendered string
|
||||
func Sprint(a ...interface{}) string {
|
||||
if len(a) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return ReplaceTag(fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Sprintf format and return rendered string
|
||||
func Sprintf(format string, a ...interface{}) string {
|
||||
return ReplaceTag(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// String alias of the ReplaceTag
|
||||
func String(s string) string {
|
||||
return ReplaceTag(s)
|
||||
}
|
||||
|
||||
// Text alias of the ReplaceTag
|
||||
func Text(s string) string {
|
||||
return ReplaceTag(s)
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* helper methods for print
|
||||
*************************************************************/
|
||||
|
||||
// new implementation, support render full color code on pwsh.exe, cmd.exe
|
||||
func doPrintV2(code, str string) {
|
||||
_, err := fmt.Fprint(output, RenderString(code, str))
|
||||
saveInternalError(err)
|
||||
|
||||
// if isLikeInCmd {
|
||||
// renderColorCodeOnCmd(func() {
|
||||
// _, _ = fmt.Fprint(output, RenderString(code, str))
|
||||
// })
|
||||
// } else {
|
||||
// _, _ = fmt.Fprint(output, RenderString(code, str))
|
||||
// }
|
||||
}
|
||||
|
||||
// new implementation, support render full color code on pwsh.exe, cmd.exe
|
||||
func doPrintlnV2(code string, args []interface{}) {
|
||||
str := formatArgsForPrintln(args)
|
||||
_, err := fmt.Fprintln(output, RenderString(code, str))
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
// if use Println, will add spaces for each arg
|
||||
func formatArgsForPrintln(args []interface{}) (message string) {
|
||||
if ln := len(args); ln == 0 {
|
||||
message = ""
|
||||
} else if ln == 1 {
|
||||
message = fmt.Sprint(args[0])
|
||||
} else {
|
||||
message = fmt.Sprintln(args...)
|
||||
// clear last "\n"
|
||||
message = message[:len(message)-1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* helper methods
|
||||
*************************************************************/
|
||||
|
||||
// is on debug mode
|
||||
// func isDebugMode() bool {
|
||||
// return debugMode == "on"
|
||||
// }
|
||||
|
||||
func debugf(f string, v ...interface{}) {
|
||||
if debugMode {
|
||||
fmt.Print("COLOR_DEBUG: ")
|
||||
fmt.Printf(f, v...)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// equals: return ok ? val1 : val2
|
||||
func compareVal(ok bool, val1, val2 uint8) uint8 {
|
||||
if ok {
|
||||
return val1
|
||||
}
|
||||
return val2
|
||||
}
|
||||
|
||||
func saveInternalError(err error) {
|
||||
if err != nil {
|
||||
debugf("inner error: %s", err.Error())
|
||||
innerErrs = append(innerErrs, err)
|
||||
}
|
||||
}
|
||||
|
||||
func stringToArr(str, sep string) (arr []string) {
|
||||
str = strings.TrimSpace(str)
|
||||
if str == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ss := strings.Split(str, sep)
|
||||
for _, val := range ss {
|
||||
if val = strings.TrimSpace(val); val != "" {
|
||||
arr = append(arr, val)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
*.out
|
||||
|
||||
# coverage
|
||||
|
||||
cover.html
|
||||
|
||||
# benchcmp
|
||||
|
||||
*.cmp
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- tip
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
|
@ -1,8 +0,0 @@
|
|||
AUTHORS
|
||||
=======
|
||||
|
||||
- Konstantin Ivanov @logrusorgru
|
||||
- Mattias Eriksson @snaggen
|
||||
- Ousmane Traore @otraore
|
||||
- Simon Legner @simon04
|
||||
- Sevenate @sevenate
|
|
@ -1,59 +0,0 @@
|
|||
Changes
|
||||
=======
|
||||
|
||||
---
|
||||
16:05:02
|
||||
Thursday, July 2, 2020
|
||||
|
||||
Change license from the WTFPL to the Unlicense due to pkg.go.dev restriction.
|
||||
|
||||
---
|
||||
15:39:40
|
||||
Wednesday, April 17, 2019
|
||||
|
||||
- Bright background and foreground colors
|
||||
- 8-bit indexed colors `Index`, `BgIndex`
|
||||
- 24 grayscale colors `Gray`, `BgGray`
|
||||
- `Yellow` and `BgYellow` methods, mark Brow and BgBrown as deprecated
|
||||
Following specifications, correct name of the colors are yellow, but
|
||||
by historical reason they are called brown. Both, the `Yellow` and the
|
||||
`Brown` methods (including `Bg+`) represents the same colors. The Brown
|
||||
are leaved for backward compatibility until Go modules production release.
|
||||
- Additional formats
|
||||
+ `Faint` that is opposite to the `Bold`
|
||||
+ `DoublyUnderline`
|
||||
+ `Fraktur`
|
||||
+ `Italic`
|
||||
+ `Underline`
|
||||
+ `SlowBlink` with `Blink` alias
|
||||
+ `RapidBlink`
|
||||
+ `Reverse` that is alias for the `Inverse`
|
||||
+ `Conceal` with `Hidden` alias
|
||||
+ `CrossedOut` with `StrikeThrough` alias
|
||||
+ `Framed`
|
||||
+ `Encircled`
|
||||
+ `Overlined`
|
||||
- Add AUTHORS.md file and change all copyright notices.
|
||||
- `Reset` method to create clear value. `Reset` method that replaces
|
||||
`Bleach` method. The `Bleach` method was marked as deprecated.
|
||||
|
||||
---
|
||||
|
||||
14:25:49
|
||||
Friday, August 18, 2017
|
||||
|
||||
- LICENSE.md changed to LICENSE
|
||||
- fix email in README.md
|
||||
- add "no warranty" to README.md
|
||||
- set proper copyright date
|
||||
|
||||
---
|
||||
|
||||
16:59:28
|
||||
Tuesday, November 8, 2016
|
||||
|
||||
- Rid out off sync.Pool
|
||||
- Little optimizations (very little)
|
||||
- Improved benchmarks
|
||||
|
||||
---
|
|
@ -1,24 +0,0 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
|
@ -1,314 +0,0 @@
|
|||
Aurora
|
||||
======
|
||||
|
||||
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/logrusorgru/aurora?tab=doc)
|
||||
[![Unlicense](https://img.shields.io/badge/license-unlicense-blue.svg)](http://unlicense.org/)
|
||||
[![Build Status](https://travis-ci.org/logrusorgru/aurora.svg)](https://travis-ci.org/logrusorgru/aurora)
|
||||
[![Coverage Status](https://coveralls.io/repos/logrusorgru/aurora/badge.svg?branch=master)](https://coveralls.io/r/logrusorgru/aurora?branch=master)
|
||||
[![GoReportCard](https://goreportcard.com/badge/logrusorgru/aurora)](https://goreportcard.com/report/logrusorgru/aurora)
|
||||
[![Gitter](https://img.shields.io/badge/chat-on_gitter-46bc99.svg?logo=data:image%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNCI%2BPGcgZmlsbD0iI2ZmZiI%2BPHJlY3QgeD0iMCIgeT0iMyIgd2lkdGg9IjEiIGhlaWdodD0iNSIvPjxyZWN0IHg9IjIiIHk9IjQiIHdpZHRoPSIxIiBoZWlnaHQ9IjciLz48cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMSIgaGVpZ2h0PSI3Ii8%2BPHJlY3QgeD0iNiIgeT0iNCIgd2lkdGg9IjEiIGhlaWdodD0iNCIvPjwvZz48L3N2Zz4%3D&logoWidth=10)](https://gitter.im/logrusorgru/aurora)
|
||||
|
||||
Ultimate ANSI colors for Golang. The package supports Printf/Sprintf etc.
|
||||
|
||||
|
||||
![aurora logo](https://github.com/logrusorgru/aurora/blob/master/gopher_aurora.png)
|
||||
|
||||
# TOC
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
+ [Simple](#simple)
|
||||
+ [Printf](#printf)
|
||||
+ [aurora.Sprintf](#aurorasprintf)
|
||||
+ [Enable/Disable colors](#enabledisable-colors)
|
||||
- [Chains](#chains)
|
||||
- [Colorize](#colorize)
|
||||
- [Grayscale](#grayscale)
|
||||
- [8-bit colors](#8-bit-colors)
|
||||
- [Supported Colors & Formats](#supported-colors--formats)
|
||||
+ [All colors](#all-colors)
|
||||
+ [Standard and bright colors](#standard-and-bright-colors)
|
||||
+ [Formats are likely supported](#formats-are-likely-supported)
|
||||
+ [Formats are likely unsupported](#formats-are-likely-unsupported)
|
||||
- [Limitations](#limitations)
|
||||
+ [Windows](#windows)
|
||||
+ [TTY](#tty)
|
||||
- [Licensing](#licensing)
|
||||
|
||||
# Installation
|
||||
|
||||
Get
|
||||
```
|
||||
go get -u github.com/logrusorgru/aurora
|
||||
```
|
||||
Test
|
||||
```
|
||||
go test -cover github.com/logrusorgru/aurora
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
### Simple
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello,", Magenta("Aurora"))
|
||||
fmt.Println(Bold(Cyan("Cya!")))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
![simple png](https://github.com/logrusorgru/aurora/blob/master/simple.png)
|
||||
|
||||
### Printf
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Got it %d times\n", Green(1240))
|
||||
fmt.Printf("PI is %+1.2e\n", Cyan(3.14))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
![printf png](https://github.com/logrusorgru/aurora/blob/master/printf.png)
|
||||
|
||||
### aurora.Sprintf
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(Sprintf(Magenta("Got it %d times"), Green(1240)))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
![sprintf png](https://github.com/logrusorgru/aurora/blob/master/sprintf.png)
|
||||
|
||||
### Enable/Disable colors
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"flag"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
// colorizer
|
||||
var au aurora.Aurora
|
||||
|
||||
var colors = flag.Bool("colors", false, "enable or disable colors")
|
||||
|
||||
func init() {
|
||||
flag.Parse()
|
||||
au = aurora.NewAurora(*colors)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// use colorizer
|
||||
fmt.Println(au.Green("Hello"))
|
||||
}
|
||||
|
||||
```
|
||||
Without flags:
|
||||
![disable png](https://github.com/logrusorgru/aurora/blob/master/disable.png)
|
||||
|
||||
With `-colors` flag:
|
||||
![enable png](https://github.com/logrusorgru/aurora/blob/master/enable.png)
|
||||
|
||||
# Chains
|
||||
|
||||
The following samples are equal
|
||||
|
||||
```go
|
||||
x := BgMagenta(Bold(Red("x")))
|
||||
```
|
||||
|
||||
```go
|
||||
x := Red("x").Bold().BgMagenta()
|
||||
```
|
||||
|
||||
The second is more readable
|
||||
|
||||
# Colorize
|
||||
|
||||
There is `Colorize` function that allows to choose some colors and
|
||||
format from a side
|
||||
|
||||
```go
|
||||
|
||||
func getColors() Color {
|
||||
// some stuff that returns appropriate colors and format
|
||||
}
|
||||
|
||||
// [...]
|
||||
|
||||
func main() {
|
||||
fmt.Println(Colorize("Greeting", getColors()))
|
||||
}
|
||||
|
||||
```
|
||||
Less complicated example
|
||||
|
||||
```go
|
||||
x := Colorize("Greeting", GreenFg|GrayBg|BoldFm)
|
||||
```
|
||||
|
||||
Unlike other color functions and methods (such as Red/BgBlue etc)
|
||||
a `Colorize` clears previous colors
|
||||
|
||||
```go
|
||||
x := Red("x").Colorize(BgGreen) // will be with green background only
|
||||
```
|
||||
|
||||
# Grayscale
|
||||
|
||||
```go
|
||||
fmt.Println(" ",
|
||||
Gray(1-1, " 00-23 ").BgGray(24-1),
|
||||
Gray(4-1, " 03-19 ").BgGray(20-1),
|
||||
Gray(8-1, " 07-15 ").BgGray(16-1),
|
||||
Gray(12-1, " 11-11 ").BgGray(12-1),
|
||||
Gray(16-1, " 15-07 ").BgGray(8-1),
|
||||
Gray(20-1, " 19-03 ").BgGray(4-1),
|
||||
Gray(24-1, " 23-00 ").BgGray(1-1),
|
||||
)
|
||||
```
|
||||
|
||||
![grayscale png](https://github.com/logrusorgru/aurora/blob/master/aurora_grayscale.png)
|
||||
|
||||
# 8-bit colors
|
||||
|
||||
Methods `Index` and `BgIndex` implements 8-bit colors.
|
||||
|
||||
| Index/BgIndex | Meaning | Foreground | Background |
|
||||
| -------------- | --------------- | ---------- | ---------- |
|
||||
| 0- 7 | standard colors | 30- 37 | 40- 47 |
|
||||
| 8- 15 | bright colors | 90- 97 | 100-107 |
|
||||
| 16-231 | 216 colors | 38;5;n | 48;5;n |
|
||||
| 232-255 | 24 grayscale | 38;5;n | 48;5;n |
|
||||
|
||||
|
||||
# Supported colors & formats
|
||||
|
||||
- formats
|
||||
+ bold (1)
|
||||
+ faint (2)
|
||||
+ doubly-underline (21)
|
||||
+ fraktur (20)
|
||||
+ italic (3)
|
||||
+ underline (4)
|
||||
+ slow blink (5)
|
||||
+ rapid blink (6)
|
||||
+ reverse video (7)
|
||||
+ conceal (8)
|
||||
+ crossed out (9)
|
||||
+ framed (51)
|
||||
+ encircled (52)
|
||||
+ overlined (53)
|
||||
- background and foreground colors, including bright
|
||||
+ black
|
||||
+ red
|
||||
+ green
|
||||
+ yellow (brown)
|
||||
+ blue
|
||||
+ magenta
|
||||
+ cyan
|
||||
+ white
|
||||
+ 24 grayscale colors
|
||||
+ 216 8-bit colors
|
||||
|
||||
### All colors
|
||||
|
||||
![linux png](https://github.com/logrusorgru/aurora/blob/master/aurora_colors_black.png)
|
||||
![white png](https://github.com/logrusorgru/aurora/blob/master/aurora_colors_white.png)
|
||||
|
||||
### Standard and bright colors
|
||||
|
||||
![linux black standard png](https://github.com/logrusorgru/aurora/blob/master/aurora_black_standard.png)
|
||||
![linux white standard png](https://github.com/logrusorgru/aurora/blob/master/aurora_white_standard.png)
|
||||
|
||||
### Formats are likely supported
|
||||
|
||||
![formats supported gif](https://github.com/logrusorgru/aurora/blob/master/aurora_formats.gif)
|
||||
|
||||
### Formats are likely unsupported
|
||||
|
||||
![formats rarely supported png](https://github.com/logrusorgru/aurora/blob/master/aurora_rarely_supported.png)
|
||||
|
||||
# Limitations
|
||||
|
||||
There is no way to represent `%T` and `%p` with colors using
|
||||
a standard approach
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := Red("red")
|
||||
var i int
|
||||
fmt.Printf("%T %p\n", r, Green(&i))
|
||||
}
|
||||
```
|
||||
|
||||
Output will be without colors
|
||||
|
||||
```
|
||||
aurora.value %!p(aurora.value={0xc42000a310 768 0})
|
||||
```
|
||||
|
||||
The obvious workaround is `Red(fmt.Sprintf("%T", some))`
|
||||
|
||||
### Windows
|
||||
|
||||
The Aurora provides ANSI colors only, so there is no support for Windows. That said, there are workarounds available.
|
||||
Check out these comments to learn more:
|
||||
|
||||
- [Using go-colorable](https://github.com/logrusorgru/aurora/issues/2#issuecomment-299014211).
|
||||
- [Using registry for Windows 10](https://github.com/logrusorgru/aurora/issues/10#issue-476361247).
|
||||
|
||||
### TTY
|
||||
|
||||
The Aurora has no internal TTY detectors by design. Take a look
|
||||
[this comment](https://github.com/logrusorgru/aurora/issues/2#issuecomment-299030108) if you want turn
|
||||
on colors for a terminal only, and turn them off for a file.
|
||||
|
||||
### Licensing
|
||||
|
||||
Copyright © 2016-2020 The Aurora Authors. This work is free.
|
||||
It comes without any warranty, to the extent permitted by applicable
|
||||
law. You can redistribute it and/or modify it under the terms of the
|
||||
the Unlicense. See the LICENSE file for more details.
|
||||
|
||||
|
|
@ -1,725 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
|
||||
// This program is free software. It comes without any warranty,
|
||||
// to the extent permitted by applicable law. You can redistribute
|
||||
// it and/or modify it under the terms of the Unlicense. See LICENSE
|
||||
// file for more details or see below.
|
||||
//
|
||||
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//
|
||||
|
||||
// Package aurora implements ANSI-colors
|
||||
package aurora
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// An Aurora implements colorizer interface.
|
||||
// It also can be a non-colorizer
|
||||
type Aurora interface {
|
||||
|
||||
// Reset wraps given argument returning Value
|
||||
// without formats and colors.
|
||||
Reset(arg interface{}) Value
|
||||
|
||||
//
|
||||
// Formats
|
||||
//
|
||||
//
|
||||
// Bold or increased intensity (1).
|
||||
Bold(arg interface{}) Value
|
||||
// Faint, decreased intensity (2).
|
||||
Faint(arg interface{}) Value
|
||||
//
|
||||
// DoublyUnderline or Bold off, double-underline
|
||||
// per ECMA-48 (21).
|
||||
DoublyUnderline(arg interface{}) Value
|
||||
// Fraktur, rarely supported (20).
|
||||
Fraktur(arg interface{}) Value
|
||||
//
|
||||
// Italic, not widely supported, sometimes
|
||||
// treated as inverse (3).
|
||||
Italic(arg interface{}) Value
|
||||
// Underline (4).
|
||||
Underline(arg interface{}) Value
|
||||
//
|
||||
// SlowBlink, blinking less than 150
|
||||
// per minute (5).
|
||||
SlowBlink(arg interface{}) Value
|
||||
// RapidBlink, blinking 150+ per minute,
|
||||
// not widely supported (6).
|
||||
RapidBlink(arg interface{}) Value
|
||||
// Blink is alias for the SlowBlink.
|
||||
Blink(arg interface{}) Value
|
||||
//
|
||||
// Reverse video, swap foreground and
|
||||
// background colors (7).
|
||||
Reverse(arg interface{}) Value
|
||||
// Inverse is alias for the Reverse
|
||||
Inverse(arg interface{}) Value
|
||||
//
|
||||
// Conceal, hidden, not widely supported (8).
|
||||
Conceal(arg interface{}) Value
|
||||
// Hidden is alias for the Conceal
|
||||
Hidden(arg interface{}) Value
|
||||
//
|
||||
// CrossedOut, characters legible, but
|
||||
// marked for deletion (9).
|
||||
CrossedOut(arg interface{}) Value
|
||||
// StrikeThrough is alias for the CrossedOut.
|
||||
StrikeThrough(arg interface{}) Value
|
||||
//
|
||||
// Framed (51).
|
||||
Framed(arg interface{}) Value
|
||||
// Encircled (52).
|
||||
Encircled(arg interface{}) Value
|
||||
//
|
||||
// Overlined (53).
|
||||
Overlined(arg interface{}) Value
|
||||
|
||||
//
|
||||
// Foreground colors
|
||||
//
|
||||
//
|
||||
// Black foreground color (30)
|
||||
Black(arg interface{}) Value
|
||||
// Red foreground color (31)
|
||||
Red(arg interface{}) Value
|
||||
// Green foreground color (32)
|
||||
Green(arg interface{}) Value
|
||||
// Yellow foreground color (33)
|
||||
Yellow(arg interface{}) Value
|
||||
// Brown foreground color (33)
|
||||
//
|
||||
// Deprecated: use Yellow instead, following specification
|
||||
Brown(arg interface{}) Value
|
||||
// Blue foreground color (34)
|
||||
Blue(arg interface{}) Value
|
||||
// Magenta foreground color (35)
|
||||
Magenta(arg interface{}) Value
|
||||
// Cyan foreground color (36)
|
||||
Cyan(arg interface{}) Value
|
||||
// White foreground color (37)
|
||||
White(arg interface{}) Value
|
||||
//
|
||||
// Bright foreground colors
|
||||
//
|
||||
// BrightBlack foreground color (90)
|
||||
BrightBlack(arg interface{}) Value
|
||||
// BrightRed foreground color (91)
|
||||
BrightRed(arg interface{}) Value
|
||||
// BrightGreen foreground color (92)
|
||||
BrightGreen(arg interface{}) Value
|
||||
// BrightYellow foreground color (93)
|
||||
BrightYellow(arg interface{}) Value
|
||||
// BrightBlue foreground color (94)
|
||||
BrightBlue(arg interface{}) Value
|
||||
// BrightMagenta foreground color (95)
|
||||
BrightMagenta(arg interface{}) Value
|
||||
// BrightCyan foreground color (96)
|
||||
BrightCyan(arg interface{}) Value
|
||||
// BrightWhite foreground color (97)
|
||||
BrightWhite(arg interface{}) Value
|
||||
//
|
||||
// Other
|
||||
//
|
||||
// Index of pre-defined 8-bit foreground color
|
||||
// from 0 to 255 (38;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 30–37 m)
|
||||
// 8- 15: high intensity colors (as in ESC [ 90–97 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
Index(n uint8, arg interface{}) Value
|
||||
// Gray from 0 to 23.
|
||||
Gray(n uint8, arg interface{}) Value
|
||||
|
||||
//
|
||||
// Background colors
|
||||
//
|
||||
//
|
||||
// BgBlack background color (40)
|
||||
BgBlack(arg interface{}) Value
|
||||
// BgRed background color (41)
|
||||
BgRed(arg interface{}) Value
|
||||
// BgGreen background color (42)
|
||||
BgGreen(arg interface{}) Value
|
||||
// BgYellow background color (43)
|
||||
BgYellow(arg interface{}) Value
|
||||
// BgBrown background color (43)
|
||||
//
|
||||
// Deprecated: use BgYellow instead, following specification
|
||||
BgBrown(arg interface{}) Value
|
||||
// BgBlue background color (44)
|
||||
BgBlue(arg interface{}) Value
|
||||
// BgMagenta background color (45)
|
||||
BgMagenta(arg interface{}) Value
|
||||
// BgCyan background color (46)
|
||||
BgCyan(arg interface{}) Value
|
||||
// BgWhite background color (47)
|
||||
BgWhite(arg interface{}) Value
|
||||
//
|
||||
// Bright background colors
|
||||
//
|
||||
// BgBrightBlack background color (100)
|
||||
BgBrightBlack(arg interface{}) Value
|
||||
// BgBrightRed background color (101)
|
||||
BgBrightRed(arg interface{}) Value
|
||||
// BgBrightGreen background color (102)
|
||||
BgBrightGreen(arg interface{}) Value
|
||||
// BgBrightYellow background color (103)
|
||||
BgBrightYellow(arg interface{}) Value
|
||||
// BgBrightBlue background color (104)
|
||||
BgBrightBlue(arg interface{}) Value
|
||||
// BgBrightMagenta background color (105)
|
||||
BgBrightMagenta(arg interface{}) Value
|
||||
// BgBrightCyan background color (106)
|
||||
BgBrightCyan(arg interface{}) Value
|
||||
// BgBrightWhite background color (107)
|
||||
BgBrightWhite(arg interface{}) Value
|
||||
//
|
||||
// Other
|
||||
//
|
||||
// BgIndex of 8-bit pre-defined background color
|
||||
// from 0 to 255 (48;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 40–47 m)
|
||||
// 8- 15: high intensity colors (as in ESC [100–107 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
BgIndex(n uint8, arg interface{}) Value
|
||||
// BgGray from 0 to 23.
|
||||
BgGray(n uint8, arg interface{}) Value
|
||||
|
||||
//
|
||||
// Special
|
||||
//
|
||||
// Colorize removes existing colors and
|
||||
// formats of the argument and applies given.
|
||||
Colorize(arg interface{}, color Color) Value
|
||||
|
||||
//
|
||||
// Support methods
|
||||
//
|
||||
// Sprintf allows to use colored format.
|
||||
Sprintf(format interface{}, args ...interface{}) string
|
||||
}
|
||||
|
||||
// NewAurora returns a new Aurora interface that
|
||||
// will support or not support colors depending
|
||||
// the enableColors argument
|
||||
func NewAurora(enableColors bool) Aurora {
|
||||
if enableColors {
|
||||
return aurora{}
|
||||
}
|
||||
return auroraClear{}
|
||||
}
|
||||
|
||||
// no colors
|
||||
|
||||
type auroraClear struct{}
|
||||
|
||||
func (auroraClear) Reset(arg interface{}) Value { return valueClear{arg} }
|
||||
|
||||
func (auroraClear) Bold(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Faint(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) DoublyUnderline(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Fraktur(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Italic(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Underline(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) SlowBlink(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) RapidBlink(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Blink(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Reverse(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Inverse(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Conceal(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Hidden(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) CrossedOut(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) StrikeThrough(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Framed(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Encircled(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Overlined(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Black(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Red(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Green(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Yellow(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Brown(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Blue(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Magenta(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Cyan(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) White(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightBlack(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightRed(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightGreen(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightYellow(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightBlue(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightMagenta(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightCyan(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BrightWhite(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Index(_ uint8, arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Gray(_ uint8, arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBlack(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgRed(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgGreen(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgYellow(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrown(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBlue(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgMagenta(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgCyan(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgWhite(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightBlack(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightRed(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightGreen(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightYellow(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightBlue(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightMagenta(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightCyan(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgBrightWhite(arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgIndex(_ uint8, arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) BgGray(_ uint8, arg interface{}) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Colorize(arg interface{}, _ Color) Value {
|
||||
return valueClear{arg}
|
||||
}
|
||||
|
||||
func (auroraClear) Sprintf(format interface{}, args ...interface{}) string {
|
||||
if str, ok := format.(string); ok {
|
||||
return fmt.Sprintf(str, args...)
|
||||
}
|
||||
return fmt.Sprintf(fmt.Sprint(format), args...)
|
||||
}
|
||||
|
||||
// colorized
|
||||
|
||||
type aurora struct{}
|
||||
|
||||
func (aurora) Reset(arg interface{}) Value {
|
||||
return Reset(arg)
|
||||
}
|
||||
|
||||
func (aurora) Bold(arg interface{}) Value {
|
||||
return Bold(arg)
|
||||
}
|
||||
|
||||
func (aurora) Faint(arg interface{}) Value {
|
||||
return Faint(arg)
|
||||
}
|
||||
|
||||
func (aurora) DoublyUnderline(arg interface{}) Value {
|
||||
return DoublyUnderline(arg)
|
||||
}
|
||||
|
||||
func (aurora) Fraktur(arg interface{}) Value {
|
||||
return Fraktur(arg)
|
||||
}
|
||||
|
||||
func (aurora) Italic(arg interface{}) Value {
|
||||
return Italic(arg)
|
||||
}
|
||||
|
||||
func (aurora) Underline(arg interface{}) Value {
|
||||
return Underline(arg)
|
||||
}
|
||||
|
||||
func (aurora) SlowBlink(arg interface{}) Value {
|
||||
return SlowBlink(arg)
|
||||
}
|
||||
|
||||
func (aurora) RapidBlink(arg interface{}) Value {
|
||||
return RapidBlink(arg)
|
||||
}
|
||||
|
||||
func (aurora) Blink(arg interface{}) Value {
|
||||
return Blink(arg)
|
||||
}
|
||||
|
||||
func (aurora) Reverse(arg interface{}) Value {
|
||||
return Reverse(arg)
|
||||
}
|
||||
|
||||
func (aurora) Inverse(arg interface{}) Value {
|
||||
return Inverse(arg)
|
||||
}
|
||||
|
||||
func (aurora) Conceal(arg interface{}) Value {
|
||||
return Conceal(arg)
|
||||
}
|
||||
|
||||
func (aurora) Hidden(arg interface{}) Value {
|
||||
return Hidden(arg)
|
||||
}
|
||||
|
||||
func (aurora) CrossedOut(arg interface{}) Value {
|
||||
return CrossedOut(arg)
|
||||
}
|
||||
|
||||
func (aurora) StrikeThrough(arg interface{}) Value {
|
||||
return StrikeThrough(arg)
|
||||
}
|
||||
|
||||
func (aurora) Framed(arg interface{}) Value {
|
||||
return Framed(arg)
|
||||
}
|
||||
|
||||
func (aurora) Encircled(arg interface{}) Value {
|
||||
return Encircled(arg)
|
||||
}
|
||||
|
||||
func (aurora) Overlined(arg interface{}) Value {
|
||||
return Overlined(arg)
|
||||
}
|
||||
|
||||
func (aurora) Black(arg interface{}) Value {
|
||||
return Black(arg)
|
||||
}
|
||||
|
||||
func (aurora) Red(arg interface{}) Value {
|
||||
return Red(arg)
|
||||
}
|
||||
|
||||
func (aurora) Green(arg interface{}) Value {
|
||||
return Green(arg)
|
||||
}
|
||||
|
||||
func (aurora) Yellow(arg interface{}) Value {
|
||||
return Yellow(arg)
|
||||
}
|
||||
|
||||
func (aurora) Brown(arg interface{}) Value {
|
||||
return Brown(arg)
|
||||
}
|
||||
|
||||
func (aurora) Blue(arg interface{}) Value {
|
||||
return Blue(arg)
|
||||
}
|
||||
|
||||
func (aurora) Magenta(arg interface{}) Value {
|
||||
return Magenta(arg)
|
||||
}
|
||||
|
||||
func (aurora) Cyan(arg interface{}) Value {
|
||||
return Cyan(arg)
|
||||
}
|
||||
|
||||
func (aurora) White(arg interface{}) Value {
|
||||
return White(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightBlack(arg interface{}) Value {
|
||||
return BrightBlack(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightRed(arg interface{}) Value {
|
||||
return BrightRed(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightGreen(arg interface{}) Value {
|
||||
return BrightGreen(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightYellow(arg interface{}) Value {
|
||||
return BrightYellow(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightBlue(arg interface{}) Value {
|
||||
return BrightBlue(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightMagenta(arg interface{}) Value {
|
||||
return BrightMagenta(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightCyan(arg interface{}) Value {
|
||||
return BrightCyan(arg)
|
||||
}
|
||||
|
||||
func (aurora) BrightWhite(arg interface{}) Value {
|
||||
return BrightWhite(arg)
|
||||
}
|
||||
|
||||
func (aurora) Index(index uint8, arg interface{}) Value {
|
||||
return Index(index, arg)
|
||||
}
|
||||
|
||||
func (aurora) Gray(n uint8, arg interface{}) Value {
|
||||
return Gray(n, arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBlack(arg interface{}) Value {
|
||||
return BgBlack(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgRed(arg interface{}) Value {
|
||||
return BgRed(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgGreen(arg interface{}) Value {
|
||||
return BgGreen(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgYellow(arg interface{}) Value {
|
||||
return BgYellow(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrown(arg interface{}) Value {
|
||||
return BgBrown(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBlue(arg interface{}) Value {
|
||||
return BgBlue(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgMagenta(arg interface{}) Value {
|
||||
return BgMagenta(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgCyan(arg interface{}) Value {
|
||||
return BgCyan(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgWhite(arg interface{}) Value {
|
||||
return BgWhite(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightBlack(arg interface{}) Value {
|
||||
return BgBrightBlack(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightRed(arg interface{}) Value {
|
||||
return BgBrightRed(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightGreen(arg interface{}) Value {
|
||||
return BgBrightGreen(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightYellow(arg interface{}) Value {
|
||||
return BgBrightYellow(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightBlue(arg interface{}) Value {
|
||||
return BgBrightBlue(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightMagenta(arg interface{}) Value {
|
||||
return BgBrightMagenta(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightCyan(arg interface{}) Value {
|
||||
return BgBrightCyan(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgBrightWhite(arg interface{}) Value {
|
||||
return BgBrightWhite(arg)
|
||||
}
|
||||
|
||||
func (aurora) BgIndex(n uint8, arg interface{}) Value {
|
||||
return BgIndex(n, arg)
|
||||
}
|
||||
|
||||
func (aurora) BgGray(n uint8, arg interface{}) Value {
|
||||
return BgGray(n, arg)
|
||||
}
|
||||
|
||||
func (aurora) Colorize(arg interface{}, color Color) Value {
|
||||
return Colorize(arg, color)
|
||||
}
|
||||
|
||||
func (aurora) Sprintf(format interface{}, args ...interface{}) string {
|
||||
return Sprintf(format, args...)
|
||||
}
|
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -1,398 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
|
||||
// This program is free software. It comes without any warranty,
|
||||
// to the extent permitted by applicable law. You can redistribute
|
||||
// it and/or modify it under the terms of the Unlicense. See LICENSE
|
||||
// file for more details or see below.
|
||||
//
|
||||
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//
|
||||
|
||||
package aurora
|
||||
|
||||
// A Color type is a color. It can contain
|
||||
// one background color, one foreground color
|
||||
// and a format, including ideogram related
|
||||
// formats.
|
||||
type Color uint
|
||||
|
||||
/*
|
||||
|
||||
Developer note.
|
||||
|
||||
The int type is architecture depended and can be
|
||||
represented as int32 or int64.
|
||||
|
||||
Thus, we can use 32-bits only to be fast and
|
||||
cross-platform.
|
||||
|
||||
All supported formats requires 14 bits. It is
|
||||
first 14 bits.
|
||||
|
||||
A foreground color requires 8 bit + 1 bit (presence flag).
|
||||
And the same for background color.
|
||||
|
||||
The Color representations
|
||||
|
||||
[ bg 8 bit ] [fg 8 bit ] [ fg/bg 2 bits ] [ fm 14 bits ]
|
||||
|
||||
https://play.golang.org/p/fq2zcNstFoF
|
||||
|
||||
*/
|
||||
|
||||
// Special formats
|
||||
const (
|
||||
BoldFm Color = 1 << iota // 1
|
||||
FaintFm // 2
|
||||
ItalicFm // 3
|
||||
UnderlineFm // 4
|
||||
SlowBlinkFm // 5
|
||||
RapidBlinkFm // 6
|
||||
ReverseFm // 7
|
||||
ConcealFm // 8
|
||||
CrossedOutFm // 9
|
||||
|
||||
FrakturFm // 20
|
||||
DoublyUnderlineFm // 21 or bold off for some systems
|
||||
|
||||
FramedFm // 51
|
||||
EncircledFm // 52
|
||||
OverlinedFm // 53
|
||||
|
||||
InverseFm = ReverseFm // alias to ReverseFm
|
||||
BlinkFm = SlowBlinkFm // alias to SlowBlinkFm
|
||||
HiddenFm = ConcealFm // alias to ConcealFm
|
||||
StrikeThroughFm = CrossedOutFm // alias to CrossedOutFm
|
||||
|
||||
maskFm = BoldFm | FaintFm |
|
||||
ItalicFm | UnderlineFm |
|
||||
SlowBlinkFm | RapidBlinkFm |
|
||||
ReverseFm |
|
||||
ConcealFm | CrossedOutFm |
|
||||
|
||||
FrakturFm | DoublyUnderlineFm |
|
||||
|
||||
FramedFm | EncircledFm | OverlinedFm
|
||||
|
||||
flagFg Color = 1 << 14 // presence flag (14th bit)
|
||||
flagBg Color = 1 << 15 // presence flag (15th bit)
|
||||
|
||||
shiftFg = 16 // shift for foreground (starting from 16th bit)
|
||||
shiftBg = 24 // shift for background (starting from 24th bit)
|
||||
)
|
||||
|
||||
// Foreground colors and related formats
|
||||
const (
|
||||
|
||||
// 8 bits
|
||||
|
||||
// [ 0; 7] - 30-37
|
||||
// [ 8; 15] - 90-97
|
||||
// [ 16; 231] - RGB
|
||||
// [232; 255] - grayscale
|
||||
|
||||
BlackFg Color = (iota << shiftFg) | flagFg // 30, 90
|
||||
RedFg // 31, 91
|
||||
GreenFg // 32, 92
|
||||
YellowFg // 33, 93
|
||||
BlueFg // 34, 94
|
||||
MagentaFg // 35, 95
|
||||
CyanFg // 36, 96
|
||||
WhiteFg // 37, 97
|
||||
|
||||
BrightFg Color = ((1 << 3) << shiftFg) | flagFg // -> 90
|
||||
|
||||
// the BrightFg itself doesn't represent
|
||||
// a color, thus it has not flagFg
|
||||
|
||||
// 5 bits
|
||||
|
||||
// BrownFg represents brown foreground color.
|
||||
//
|
||||
// Deprecated: use YellowFg instead, following specifications
|
||||
BrownFg = YellowFg
|
||||
|
||||
//
|
||||
maskFg = (0xff << shiftFg) | flagFg
|
||||
)
|
||||
|
||||
// Background colors and related formats
|
||||
const (
|
||||
|
||||
// 8 bits
|
||||
|
||||
// [ 0; 7] - 40-47
|
||||
// [ 8; 15] - 100-107
|
||||
// [ 16; 231] - RGB
|
||||
// [232; 255] - grayscale
|
||||
|
||||
BlackBg Color = (iota << shiftBg) | flagBg // 40, 100
|
||||
RedBg // 41, 101
|
||||
GreenBg // 42, 102
|
||||
YellowBg // 43, 103
|
||||
BlueBg // 44, 104
|
||||
MagentaBg // 45, 105
|
||||
CyanBg // 46, 106
|
||||
WhiteBg // 47, 107
|
||||
|
||||
BrightBg Color = ((1 << 3) << shiftBg) | flagBg // -> 100
|
||||
|
||||
// the BrightBg itself doesn't represent
|
||||
// a color, thus it has not flagBg
|
||||
|
||||
// 5 bits
|
||||
|
||||
// BrownBg represents brown foreground color.
|
||||
//
|
||||
// Deprecated: use YellowBg instead, following specifications
|
||||
BrownBg = YellowBg
|
||||
|
||||
//
|
||||
maskBg = (0xff << shiftBg) | flagBg
|
||||
)
|
||||
|
||||
const (
|
||||
availFlags = "-+# 0"
|
||||
esc = "\033["
|
||||
clear = esc + "0m"
|
||||
)
|
||||
|
||||
// IsValid returns true always
|
||||
//
|
||||
// Deprecated: don't use this method anymore
|
||||
func (c Color) IsValid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Nos returns string like 1;7;31;45. It
|
||||
// may be an empty string for empty color.
|
||||
// If the zero is true, then the string
|
||||
// is prepended with 0;
|
||||
func (c Color) Nos(zero bool) string {
|
||||
return string(c.appendNos(make([]byte, 0, 59), zero))
|
||||
}
|
||||
|
||||
func appendCond(bs []byte, cond, semi bool, vals ...byte) []byte {
|
||||
if !cond {
|
||||
return bs
|
||||
}
|
||||
return appendSemi(bs, semi, vals...)
|
||||
}
|
||||
|
||||
// if the semi is true, then prepend with semicolon
|
||||
func appendSemi(bs []byte, semi bool, vals ...byte) []byte {
|
||||
if semi {
|
||||
bs = append(bs, ';')
|
||||
}
|
||||
return append(bs, vals...)
|
||||
}
|
||||
|
||||
func itoa(t byte) string {
|
||||
var (
|
||||
a [3]byte
|
||||
j = 2
|
||||
)
|
||||
for i := 0; i < 3; i, j = i+1, j-1 {
|
||||
a[j] = '0' + t%10
|
||||
if t = t / 10; t == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(a[j:])
|
||||
}
|
||||
|
||||
func (c Color) appendFg(bs []byte, zero bool) []byte {
|
||||
|
||||
if zero || c&maskFm != 0 {
|
||||
bs = append(bs, ';')
|
||||
}
|
||||
|
||||
// 0- 7 : 30-37
|
||||
// 8-15 : 90-97
|
||||
// > 15 : 38;5;val
|
||||
|
||||
switch fg := (c & maskFg) >> shiftFg; {
|
||||
case fg <= 7:
|
||||
// '3' and the value itself
|
||||
bs = append(bs, '3', '0'+byte(fg))
|
||||
case fg <= 15:
|
||||
// '9' and the value itself
|
||||
bs = append(bs, '9', '0'+byte(fg&^0x08)) // clear bright flag
|
||||
default:
|
||||
bs = append(bs, '3', '8', ';', '5', ';')
|
||||
bs = append(bs, itoa(byte(fg))...)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func (c Color) appendBg(bs []byte, zero bool) []byte {
|
||||
|
||||
if zero || c&(maskFm|maskFg) != 0 {
|
||||
bs = append(bs, ';')
|
||||
}
|
||||
|
||||
// 0- 7 : 40- 47
|
||||
// 8-15 : 100-107
|
||||
// > 15 : 48;5;val
|
||||
|
||||
switch fg := (c & maskBg) >> shiftBg; {
|
||||
case fg <= 7:
|
||||
// '3' and the value itself
|
||||
bs = append(bs, '4', '0'+byte(fg))
|
||||
case fg <= 15:
|
||||
// '1', '0' and the value itself
|
||||
bs = append(bs, '1', '0', '0'+byte(fg&^0x08)) // clear bright flag
|
||||
default:
|
||||
bs = append(bs, '4', '8', ';', '5', ';')
|
||||
bs = append(bs, itoa(byte(fg))...)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func (c Color) appendFm9(bs []byte, zero bool) []byte {
|
||||
|
||||
bs = appendCond(bs, c&ItalicFm != 0,
|
||||
zero || c&(BoldFm|FaintFm) != 0,
|
||||
'3')
|
||||
bs = appendCond(bs, c&UnderlineFm != 0,
|
||||
zero || c&(BoldFm|FaintFm|ItalicFm) != 0,
|
||||
'4')
|
||||
// don't combine slow and rapid blink using only
|
||||
// on of them, preferring slow blink
|
||||
if c&SlowBlinkFm != 0 {
|
||||
bs = appendSemi(bs,
|
||||
zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
|
||||
'5')
|
||||
} else if c&RapidBlinkFm != 0 {
|
||||
bs = appendSemi(bs,
|
||||
zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
|
||||
'6')
|
||||
}
|
||||
|
||||
// including 1-2
|
||||
const mask6i = BoldFm | FaintFm |
|
||||
ItalicFm | UnderlineFm |
|
||||
SlowBlinkFm | RapidBlinkFm
|
||||
|
||||
bs = appendCond(bs, c&ReverseFm != 0,
|
||||
zero || c&(mask6i) != 0,
|
||||
'7')
|
||||
bs = appendCond(bs, c&ConcealFm != 0,
|
||||
zero || c&(mask6i|ReverseFm) != 0,
|
||||
'8')
|
||||
bs = appendCond(bs, c&CrossedOutFm != 0,
|
||||
zero || c&(mask6i|ReverseFm|ConcealFm) != 0,
|
||||
'9')
|
||||
|
||||
return bs
|
||||
}
|
||||
|
||||
// append 1;3;38;5;216 like string that represents ANSI
|
||||
// color of the Color; the zero argument requires
|
||||
// appending of '0' before to reset previous format
|
||||
// and colors
|
||||
func (c Color) appendNos(bs []byte, zero bool) []byte {
|
||||
|
||||
if zero {
|
||||
bs = append(bs, '0') // reset previous
|
||||
}
|
||||
|
||||
// formats
|
||||
//
|
||||
|
||||
if c&maskFm != 0 {
|
||||
|
||||
// 1-2
|
||||
|
||||
// don't combine bold and faint using only on of them, preferring bold
|
||||
|
||||
if c&BoldFm != 0 {
|
||||
bs = appendSemi(bs, zero, '1')
|
||||
} else if c&FaintFm != 0 {
|
||||
bs = appendSemi(bs, zero, '2')
|
||||
}
|
||||
|
||||
// 3-9
|
||||
|
||||
const mask9 = ItalicFm | UnderlineFm |
|
||||
SlowBlinkFm | RapidBlinkFm |
|
||||
ReverseFm | ConcealFm | CrossedOutFm
|
||||
|
||||
if c&mask9 != 0 {
|
||||
bs = c.appendFm9(bs, zero)
|
||||
}
|
||||
|
||||
// 20-21
|
||||
|
||||
const (
|
||||
mask21 = FrakturFm | DoublyUnderlineFm
|
||||
mask9i = BoldFm | FaintFm | mask9
|
||||
)
|
||||
|
||||
if c&mask21 != 0 {
|
||||
bs = appendCond(bs, c&FrakturFm != 0,
|
||||
zero || c&mask9i != 0,
|
||||
'2', '0')
|
||||
bs = appendCond(bs, c&DoublyUnderlineFm != 0,
|
||||
zero || c&(mask9i|FrakturFm) != 0,
|
||||
'2', '1')
|
||||
}
|
||||
|
||||
// 50-53
|
||||
|
||||
const (
|
||||
mask53 = FramedFm | EncircledFm | OverlinedFm
|
||||
mask21i = mask9i | mask21
|
||||
)
|
||||
|
||||
if c&mask53 != 0 {
|
||||
bs = appendCond(bs, c&FramedFm != 0,
|
||||
zero || c&mask21i != 0,
|
||||
'5', '1')
|
||||
bs = appendCond(bs, c&EncircledFm != 0,
|
||||
zero || c&(mask21i|FramedFm) != 0,
|
||||
'5', '2')
|
||||
bs = appendCond(bs, c&OverlinedFm != 0,
|
||||
zero || c&(mask21i|FramedFm|EncircledFm) != 0,
|
||||
'5', '3')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// foreground
|
||||
if c&maskFg != 0 {
|
||||
bs = c.appendFg(bs, zero)
|
||||
}
|
||||
|
||||
// background
|
||||
if c&maskBg != 0 {
|
||||
bs = c.appendBg(bs, zero)
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
Before Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.1 KiB |
|
@ -1,68 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
|
||||
// This program is free software. It comes without any warranty,
|
||||
// to the extent permitted by applicable law. You can redistribute
|
||||
// it and/or modify it under the terms of the Unlicense. See LICENSE
|
||||
// file for more details or see below.
|
||||
//
|
||||
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//
|
||||
|
||||
package aurora
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Sprintf allows to use Value as format. For example
|
||||
//
|
||||
// v := Sprintf(Red("total: +3.5f points"), Blue(3.14))
|
||||
//
|
||||
// In this case "total:" and "points" will be red, but
|
||||
// 3.14 will be blue. But, in another example
|
||||
//
|
||||
// v := Sprintf(Red("total: +3.5f points"), 3.14)
|
||||
//
|
||||
// full string will be red. And no way to clear 3.14 to
|
||||
// default format and color
|
||||
func Sprintf(format interface{}, args ...interface{}) string {
|
||||
switch ft := format.(type) {
|
||||
case string:
|
||||
return fmt.Sprintf(ft, args...)
|
||||
case Value:
|
||||
for i, v := range args {
|
||||
if val, ok := v.(Value); ok {
|
||||
args[i] = val.setTail(ft.Color())
|
||||
continue
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf(ft.String(), args...)
|
||||
}
|
||||
// unknown type of format (we hope it's a string)
|
||||
return fmt.Sprintf(fmt.Sprint(format), args...)
|
||||
}
|
Before Width: | Height: | Size: 1.8 KiB |
|
@ -1,745 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
|
||||
// This program is free software. It comes without any warranty,
|
||||
// to the extent permitted by applicable law. You can redistribute
|
||||
// it and/or modify it under the terms of the Unlicense. See LICENSE
|
||||
// file for more details or see below.
|
||||
//
|
||||
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//
|
||||
|
||||
package aurora
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A Value represents any printable value
|
||||
// with it's color
|
||||
type Value interface {
|
||||
// String returns string with colors. If there are any color
|
||||
// or format the string will be terminated with \033[0m
|
||||
fmt.Stringer
|
||||
// Format implements fmt.Formatter interface
|
||||
fmt.Formatter
|
||||
// Color returns value's color
|
||||
Color() Color
|
||||
// Value returns value's value (welcome to the tautology club)
|
||||
Value() interface{}
|
||||
|
||||
// internals
|
||||
tail() Color
|
||||
setTail(Color) Value
|
||||
|
||||
// Bleach returns copy of original value without colors
|
||||
//
|
||||
// Deprecated: use Reset instead.
|
||||
Bleach() Value
|
||||
// Reset colors and formats
|
||||
Reset() Value
|
||||
|
||||
//
|
||||
// Formats
|
||||
//
|
||||
//
|
||||
// Bold or increased intensity (1).
|
||||
Bold() Value
|
||||
// Faint, decreased intensity, reset the Bold (2).
|
||||
Faint() Value
|
||||
//
|
||||
// DoublyUnderline or Bold off, double-underline
|
||||
// per ECMA-48 (21). It depends.
|
||||
DoublyUnderline() Value
|
||||
// Fraktur, rarely supported (20).
|
||||
Fraktur() Value
|
||||
//
|
||||
// Italic, not widely supported, sometimes
|
||||
// treated as inverse (3).
|
||||
Italic() Value
|
||||
// Underline (4).
|
||||
Underline() Value
|
||||
//
|
||||
// SlowBlink, blinking less than 150
|
||||
// per minute (5).
|
||||
SlowBlink() Value
|
||||
// RapidBlink, blinking 150+ per minute,
|
||||
// not widely supported (6).
|
||||
RapidBlink() Value
|
||||
// Blink is alias for the SlowBlink.
|
||||
Blink() Value
|
||||
//
|
||||
// Reverse video, swap foreground and
|
||||
// background colors (7).
|
||||
Reverse() Value
|
||||
// Inverse is alias for the Reverse
|
||||
Inverse() Value
|
||||
//
|
||||
// Conceal, hidden, not widely supported (8).
|
||||
Conceal() Value
|
||||
// Hidden is alias for the Conceal
|
||||
Hidden() Value
|
||||
//
|
||||
// CrossedOut, characters legible, but
|
||||
// marked for deletion (9).
|
||||
CrossedOut() Value
|
||||
// StrikeThrough is alias for the CrossedOut.
|
||||
StrikeThrough() Value
|
||||
//
|
||||
// Framed (51).
|
||||
Framed() Value
|
||||
// Encircled (52).
|
||||
Encircled() Value
|
||||
//
|
||||
// Overlined (53).
|
||||
Overlined() Value
|
||||
|
||||
//
|
||||
// Foreground colors
|
||||
//
|
||||
//
|
||||
// Black foreground color (30)
|
||||
Black() Value
|
||||
// Red foreground color (31)
|
||||
Red() Value
|
||||
// Green foreground color (32)
|
||||
Green() Value
|
||||
// Yellow foreground color (33)
|
||||
Yellow() Value
|
||||
// Brown foreground color (33)
|
||||
//
|
||||
// Deprecated: use Yellow instead, following specification
|
||||
Brown() Value
|
||||
// Blue foreground color (34)
|
||||
Blue() Value
|
||||
// Magenta foreground color (35)
|
||||
Magenta() Value
|
||||
// Cyan foreground color (36)
|
||||
Cyan() Value
|
||||
// White foreground color (37)
|
||||
White() Value
|
||||
//
|
||||
// Bright foreground colors
|
||||
//
|
||||
// BrightBlack foreground color (90)
|
||||
BrightBlack() Value
|
||||
// BrightRed foreground color (91)
|
||||
BrightRed() Value
|
||||
// BrightGreen foreground color (92)
|
||||
BrightGreen() Value
|
||||
// BrightYellow foreground color (93)
|
||||
BrightYellow() Value
|
||||
// BrightBlue foreground color (94)
|
||||
BrightBlue() Value
|
||||
// BrightMagenta foreground color (95)
|
||||
BrightMagenta() Value
|
||||
// BrightCyan foreground color (96)
|
||||
BrightCyan() Value
|
||||
// BrightWhite foreground color (97)
|
||||
BrightWhite() Value
|
||||
//
|
||||
// Other
|
||||
//
|
||||
// Index of pre-defined 8-bit foreground color
|
||||
// from 0 to 255 (38;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 30–37 m)
|
||||
// 8- 15: high intensity colors (as in ESC [ 90–97 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
Index(n uint8) Value
|
||||
// Gray from 0 to 24.
|
||||
Gray(n uint8) Value
|
||||
|
||||
//
|
||||
// Background colors
|
||||
//
|
||||
//
|
||||
// BgBlack background color (40)
|
||||
BgBlack() Value
|
||||
// BgRed background color (41)
|
||||
BgRed() Value
|
||||
// BgGreen background color (42)
|
||||
BgGreen() Value
|
||||
// BgYellow background color (43)
|
||||
BgYellow() Value
|
||||
// BgBrown background color (43)
|
||||
//
|
||||
// Deprecated: use BgYellow instead, following specification
|
||||
BgBrown() Value
|
||||
// BgBlue background color (44)
|
||||
BgBlue() Value
|
||||
// BgMagenta background color (45)
|
||||
BgMagenta() Value
|
||||
// BgCyan background color (46)
|
||||
BgCyan() Value
|
||||
// BgWhite background color (47)
|
||||
BgWhite() Value
|
||||
//
|
||||
// Bright background colors
|
||||
//
|
||||
// BgBrightBlack background color (100)
|
||||
BgBrightBlack() Value
|
||||
// BgBrightRed background color (101)
|
||||
BgBrightRed() Value
|
||||
// BgBrightGreen background color (102)
|
||||
BgBrightGreen() Value
|
||||
// BgBrightYellow background color (103)
|
||||
BgBrightYellow() Value
|
||||
// BgBrightBlue background color (104)
|
||||
BgBrightBlue() Value
|
||||
// BgBrightMagenta background color (105)
|
||||
BgBrightMagenta() Value
|
||||
// BgBrightCyan background color (106)
|
||||
BgBrightCyan() Value
|
||||
// BgBrightWhite background color (107)
|
||||
BgBrightWhite() Value
|
||||
//
|
||||
// Other
|
||||
//
|
||||
// BgIndex of 8-bit pre-defined background color
|
||||
// from 0 to 255 (48;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 40–47 m)
|
||||
// 8- 15: high intensity colors (as in ESC [100–107 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
BgIndex(n uint8) Value
|
||||
// BgGray from 0 to 24.
|
||||
BgGray(n uint8) Value
|
||||
|
||||
//
|
||||
// Special
|
||||
//
|
||||
// Colorize removes existing colors and
|
||||
// formats of the argument and applies given.
|
||||
Colorize(color Color) Value
|
||||
}
|
||||
|
||||
// Value without colors
|
||||
|
||||
type valueClear struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (vc valueClear) String() string { return fmt.Sprint(vc.value) }
|
||||
|
||||
func (vc valueClear) Color() Color { return 0 }
|
||||
func (vc valueClear) Value() interface{} { return vc.value }
|
||||
|
||||
func (vc valueClear) tail() Color { return 0 }
|
||||
func (vc valueClear) setTail(Color) Value { return vc }
|
||||
|
||||
func (vc valueClear) Bleach() Value { return vc }
|
||||
func (vc valueClear) Reset() Value { return vc }
|
||||
|
||||
func (vc valueClear) Bold() Value { return vc }
|
||||
func (vc valueClear) Faint() Value { return vc }
|
||||
func (vc valueClear) DoublyUnderline() Value { return vc }
|
||||
func (vc valueClear) Fraktur() Value { return vc }
|
||||
func (vc valueClear) Italic() Value { return vc }
|
||||
func (vc valueClear) Underline() Value { return vc }
|
||||
func (vc valueClear) SlowBlink() Value { return vc }
|
||||
func (vc valueClear) RapidBlink() Value { return vc }
|
||||
func (vc valueClear) Blink() Value { return vc }
|
||||
func (vc valueClear) Reverse() Value { return vc }
|
||||
func (vc valueClear) Inverse() Value { return vc }
|
||||
func (vc valueClear) Conceal() Value { return vc }
|
||||
func (vc valueClear) Hidden() Value { return vc }
|
||||
func (vc valueClear) CrossedOut() Value { return vc }
|
||||
func (vc valueClear) StrikeThrough() Value { return vc }
|
||||
func (vc valueClear) Framed() Value { return vc }
|
||||
func (vc valueClear) Encircled() Value { return vc }
|
||||
func (vc valueClear) Overlined() Value { return vc }
|
||||
|
||||
func (vc valueClear) Black() Value { return vc }
|
||||
func (vc valueClear) Red() Value { return vc }
|
||||
func (vc valueClear) Green() Value { return vc }
|
||||
func (vc valueClear) Yellow() Value { return vc }
|
||||
func (vc valueClear) Brown() Value { return vc }
|
||||
func (vc valueClear) Blue() Value { return vc }
|
||||
func (vc valueClear) Magenta() Value { return vc }
|
||||
func (vc valueClear) Cyan() Value { return vc }
|
||||
func (vc valueClear) White() Value { return vc }
|
||||
func (vc valueClear) BrightBlack() Value { return vc }
|
||||
func (vc valueClear) BrightRed() Value { return vc }
|
||||
func (vc valueClear) BrightGreen() Value { return vc }
|
||||
func (vc valueClear) BrightYellow() Value { return vc }
|
||||
func (vc valueClear) BrightBlue() Value { return vc }
|
||||
func (vc valueClear) BrightMagenta() Value { return vc }
|
||||
func (vc valueClear) BrightCyan() Value { return vc }
|
||||
func (vc valueClear) BrightWhite() Value { return vc }
|
||||
func (vc valueClear) Index(uint8) Value { return vc }
|
||||
func (vc valueClear) Gray(uint8) Value { return vc }
|
||||
|
||||
func (vc valueClear) BgBlack() Value { return vc }
|
||||
func (vc valueClear) BgRed() Value { return vc }
|
||||
func (vc valueClear) BgGreen() Value { return vc }
|
||||
func (vc valueClear) BgYellow() Value { return vc }
|
||||
func (vc valueClear) BgBrown() Value { return vc }
|
||||
func (vc valueClear) BgBlue() Value { return vc }
|
||||
func (vc valueClear) BgMagenta() Value { return vc }
|
||||
func (vc valueClear) BgCyan() Value { return vc }
|
||||
func (vc valueClear) BgWhite() Value { return vc }
|
||||
func (vc valueClear) BgBrightBlack() Value { return vc }
|
||||
func (vc valueClear) BgBrightRed() Value { return vc }
|
||||
func (vc valueClear) BgBrightGreen() Value { return vc }
|
||||
func (vc valueClear) BgBrightYellow() Value { return vc }
|
||||
func (vc valueClear) BgBrightBlue() Value { return vc }
|
||||
func (vc valueClear) BgBrightMagenta() Value { return vc }
|
||||
func (vc valueClear) BgBrightCyan() Value { return vc }
|
||||
func (vc valueClear) BgBrightWhite() Value { return vc }
|
||||
func (vc valueClear) BgIndex(uint8) Value { return vc }
|
||||
func (vc valueClear) BgGray(uint8) Value { return vc }
|
||||
func (vc valueClear) Colorize(Color) Value { return vc }
|
||||
|
||||
func (vc valueClear) Format(s fmt.State, verb rune) {
|
||||
// it's enough for many cases (%-+020.10f)
|
||||
// % - 1
|
||||
// availFlags - 3 (5)
|
||||
// width - 2
|
||||
// prec - 3 (.23)
|
||||
// verb - 1
|
||||
// --------------
|
||||
// 10
|
||||
format := make([]byte, 1, 10)
|
||||
format[0] = '%'
|
||||
var f byte
|
||||
for i := 0; i < len(availFlags); i++ {
|
||||
if f = availFlags[i]; s.Flag(int(f)) {
|
||||
format = append(format, f)
|
||||
}
|
||||
}
|
||||
var width, prec int
|
||||
var ok bool
|
||||
if width, ok = s.Width(); ok {
|
||||
format = strconv.AppendInt(format, int64(width), 10)
|
||||
}
|
||||
if prec, ok = s.Precision(); ok {
|
||||
format = append(format, '.')
|
||||
format = strconv.AppendInt(format, int64(prec), 10)
|
||||
}
|
||||
if verb > utf8.RuneSelf {
|
||||
format = append(format, string(verb)...)
|
||||
} else {
|
||||
format = append(format, byte(verb))
|
||||
}
|
||||
fmt.Fprintf(s, string(format), vc.value)
|
||||
}
|
||||
|
||||
// Value within colors
|
||||
|
||||
type value struct {
|
||||
value interface{} // value as it
|
||||
color Color // this color
|
||||
tailColor Color // tail color
|
||||
}
|
||||
|
||||
func (v value) String() string {
|
||||
if v.color != 0 {
|
||||
if v.tailColor != 0 {
|
||||
return esc + v.color.Nos(true) + "m" +
|
||||
fmt.Sprint(v.value) +
|
||||
esc + v.tailColor.Nos(true) + "m"
|
||||
}
|
||||
return esc + v.color.Nos(false) + "m" + fmt.Sprint(v.value) + clear
|
||||
}
|
||||
return fmt.Sprint(v.value)
|
||||
}
|
||||
|
||||
func (v value) Color() Color { return v.color }
|
||||
|
||||
func (v value) Bleach() Value {
|
||||
v.color, v.tailColor = 0, 0
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Reset() Value {
|
||||
v.color, v.tailColor = 0, 0
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) tail() Color { return v.tailColor }
|
||||
|
||||
func (v value) setTail(t Color) Value {
|
||||
v.tailColor = t
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Value() interface{} { return v.value }
|
||||
|
||||
func (v value) Format(s fmt.State, verb rune) {
|
||||
|
||||
// it's enough for many cases (%-+020.10f)
|
||||
// % - 1
|
||||
// availFlags - 3 (5)
|
||||
// width - 2
|
||||
// prec - 3 (.23)
|
||||
// verb - 1
|
||||
// --------------
|
||||
// 10
|
||||
// +
|
||||
// \033[ 5
|
||||
// 0;1;3;4;5;7;8;9;20;21;51;52;53 30
|
||||
// 38;5;216 8
|
||||
// 48;5;216 8
|
||||
// m 1
|
||||
// +
|
||||
// \033[0m 7
|
||||
//
|
||||
// x2 (possible tail color)
|
||||
//
|
||||
// 10 + 59 * 2 = 128
|
||||
|
||||
format := make([]byte, 0, 128)
|
||||
if v.color != 0 {
|
||||
format = append(format, esc...)
|
||||
format = v.color.appendNos(format, v.tailColor != 0)
|
||||
format = append(format, 'm')
|
||||
}
|
||||
format = append(format, '%')
|
||||
var f byte
|
||||
for i := 0; i < len(availFlags); i++ {
|
||||
if f = availFlags[i]; s.Flag(int(f)) {
|
||||
format = append(format, f)
|
||||
}
|
||||
}
|
||||
var width, prec int
|
||||
var ok bool
|
||||
if width, ok = s.Width(); ok {
|
||||
format = strconv.AppendInt(format, int64(width), 10)
|
||||
}
|
||||
if prec, ok = s.Precision(); ok {
|
||||
format = append(format, '.')
|
||||
format = strconv.AppendInt(format, int64(prec), 10)
|
||||
}
|
||||
if verb > utf8.RuneSelf {
|
||||
format = append(format, string(verb)...)
|
||||
} else {
|
||||
format = append(format, byte(verb))
|
||||
}
|
||||
if v.color != 0 {
|
||||
if v.tailColor != 0 {
|
||||
// set next (previous) format clearing current one
|
||||
format = append(format, esc...)
|
||||
format = v.tailColor.appendNos(format, true)
|
||||
format = append(format, 'm')
|
||||
} else {
|
||||
format = append(format, clear...) // just clear
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(s, string(format), v.value)
|
||||
}
|
||||
|
||||
func (v value) Bold() Value {
|
||||
v.color = (v.color &^ FaintFm) | BoldFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Faint() Value {
|
||||
v.color = (v.color &^ BoldFm) | FaintFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) DoublyUnderline() Value {
|
||||
v.color |= DoublyUnderlineFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Fraktur() Value {
|
||||
v.color |= FrakturFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Italic() Value {
|
||||
v.color |= ItalicFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Underline() Value {
|
||||
v.color |= UnderlineFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) SlowBlink() Value {
|
||||
v.color = (v.color &^ RapidBlinkFm) | SlowBlinkFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) RapidBlink() Value {
|
||||
v.color = (v.color &^ SlowBlinkFm) | RapidBlinkFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Blink() Value {
|
||||
return v.SlowBlink()
|
||||
}
|
||||
|
||||
func (v value) Reverse() Value {
|
||||
v.color |= ReverseFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Inverse() Value {
|
||||
return v.Reverse()
|
||||
}
|
||||
|
||||
func (v value) Conceal() Value {
|
||||
v.color |= ConcealFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Hidden() Value {
|
||||
return v.Conceal()
|
||||
}
|
||||
|
||||
func (v value) CrossedOut() Value {
|
||||
v.color |= CrossedOutFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) StrikeThrough() Value {
|
||||
return v.CrossedOut()
|
||||
}
|
||||
|
||||
func (v value) Framed() Value {
|
||||
v.color |= FramedFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Encircled() Value {
|
||||
v.color |= EncircledFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Overlined() Value {
|
||||
v.color |= OverlinedFm
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Black() Value {
|
||||
v.color = (v.color &^ maskFg) | BlackFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Red() Value {
|
||||
v.color = (v.color &^ maskFg) | RedFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Green() Value {
|
||||
v.color = (v.color &^ maskFg) | GreenFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Yellow() Value {
|
||||
v.color = (v.color &^ maskFg) | YellowFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Brown() Value {
|
||||
return v.Yellow()
|
||||
}
|
||||
|
||||
func (v value) Blue() Value {
|
||||
v.color = (v.color &^ maskFg) | BlueFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Magenta() Value {
|
||||
v.color = (v.color &^ maskFg) | MagentaFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Cyan() Value {
|
||||
v.color = (v.color &^ maskFg) | CyanFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) White() Value {
|
||||
v.color = (v.color &^ maskFg) | WhiteFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightBlack() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | BlackFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightRed() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | RedFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightGreen() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | GreenFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightYellow() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | YellowFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightBlue() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | BlueFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightMagenta() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | MagentaFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightCyan() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | CyanFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BrightWhite() Value {
|
||||
v.color = (v.color &^ maskFg) | BrightFg | WhiteFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Index(n uint8) Value {
|
||||
v.color = (v.color &^ maskFg) | (Color(n) << shiftFg) | flagFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Gray(n uint8) Value {
|
||||
if n > 23 {
|
||||
n = 23
|
||||
}
|
||||
v.color = (v.color &^ maskFg) | (Color(232+n) << shiftFg) | flagFg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBlack() Value {
|
||||
v.color = (v.color &^ maskBg) | BlackBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgRed() Value {
|
||||
v.color = (v.color &^ maskBg) | RedBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgGreen() Value {
|
||||
v.color = (v.color &^ maskBg) | GreenBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgYellow() Value {
|
||||
v.color = (v.color &^ maskBg) | YellowBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrown() Value {
|
||||
return v.BgYellow()
|
||||
}
|
||||
|
||||
func (v value) BgBlue() Value {
|
||||
v.color = (v.color &^ maskBg) | BlueBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgMagenta() Value {
|
||||
v.color = (v.color &^ maskBg) | MagentaBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgCyan() Value {
|
||||
v.color = (v.color &^ maskBg) | CyanBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgWhite() Value {
|
||||
v.color = (v.color &^ maskBg) | WhiteBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightBlack() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | BlackBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightRed() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | RedBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightGreen() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | GreenBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightYellow() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | YellowBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightBlue() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | BlueBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightMagenta() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | MagentaBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightCyan() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | CyanBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgBrightWhite() Value {
|
||||
v.color = (v.color &^ maskBg) | BrightBg | WhiteBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgIndex(n uint8) Value {
|
||||
v.color = (v.color &^ maskBg) | (Color(n) << shiftBg) | flagBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) BgGray(n uint8) Value {
|
||||
if n > 23 {
|
||||
n = 23
|
||||
}
|
||||
v.color = (v.color &^ maskBg) | (Color(232+n) << shiftBg) | flagBg
|
||||
return v
|
||||
}
|
||||
|
||||
func (v value) Colorize(color Color) Value {
|
||||
v.color = color
|
||||
return v
|
||||
}
|
|
@ -1,558 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
|
||||
// This program is free software. It comes without any warranty,
|
||||
// to the extent permitted by applicable law. You can redistribute
|
||||
// it and/or modify it under the terms of the Unlicense. See LICENSE
|
||||
// file for more details or see below.
|
||||
//
|
||||
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//
|
||||
|
||||
package aurora
|
||||
|
||||
// Colorize wraps given value into Value with
|
||||
// given colors. For example
|
||||
//
|
||||
// s := Colorize("some", BlueFg|GreenBg|BoldFm)
|
||||
//
|
||||
// returns a Value with blue foreground, green
|
||||
// background and bold. Unlike functions like
|
||||
// Red/BgBlue/Bold etc. This function clears
|
||||
// all previous colors and formats. Thus
|
||||
//
|
||||
// s := Colorize(Red("some"), BgBlue)
|
||||
//
|
||||
// clears red color from value
|
||||
func Colorize(arg interface{}, color Color) Value {
|
||||
if val, ok := arg.(value); ok {
|
||||
val.color = color
|
||||
return val
|
||||
}
|
||||
return value{arg, color, 0}
|
||||
}
|
||||
|
||||
// Reset wraps given argument returning Value
|
||||
// without formats and colors.
|
||||
func Reset(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Reset()
|
||||
}
|
||||
return value{value: arg}
|
||||
}
|
||||
|
||||
//
|
||||
// Formats
|
||||
//
|
||||
|
||||
// Bold or increased intensity (1).
|
||||
func Bold(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Bold()
|
||||
}
|
||||
return value{value: arg, color: BoldFm}
|
||||
}
|
||||
|
||||
// Faint decreases intensity (2).
|
||||
// The Faint rejects the Bold.
|
||||
func Faint(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Faint()
|
||||
}
|
||||
return value{value: arg, color: FaintFm}
|
||||
}
|
||||
|
||||
// DoublyUnderline or Bold off, double-underline
|
||||
// per ECMA-48 (21).
|
||||
func DoublyUnderline(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.DoublyUnderline()
|
||||
}
|
||||
return value{value: arg, color: DoublyUnderlineFm}
|
||||
}
|
||||
|
||||
// Fraktur is rarely supported (20).
|
||||
func Fraktur(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Fraktur()
|
||||
}
|
||||
return value{value: arg, color: FrakturFm}
|
||||
}
|
||||
|
||||
// Italic is not widely supported, sometimes
|
||||
// treated as inverse (3).
|
||||
func Italic(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Italic()
|
||||
}
|
||||
return value{value: arg, color: ItalicFm}
|
||||
}
|
||||
|
||||
// Underline (4).
|
||||
func Underline(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Underline()
|
||||
}
|
||||
return value{value: arg, color: UnderlineFm}
|
||||
}
|
||||
|
||||
// SlowBlink makes text blink less than
|
||||
// 150 per minute (5).
|
||||
func SlowBlink(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.SlowBlink()
|
||||
}
|
||||
return value{value: arg, color: SlowBlinkFm}
|
||||
}
|
||||
|
||||
// RapidBlink makes text blink 150+ per
|
||||
// minute. It is not widely supported (6).
|
||||
func RapidBlink(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.RapidBlink()
|
||||
}
|
||||
return value{value: arg, color: RapidBlinkFm}
|
||||
}
|
||||
|
||||
// Blink is alias for the SlowBlink.
|
||||
func Blink(arg interface{}) Value {
|
||||
return SlowBlink(arg)
|
||||
}
|
||||
|
||||
// Reverse video, swap foreground and
|
||||
// background colors (7).
|
||||
func Reverse(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Reverse()
|
||||
}
|
||||
return value{value: arg, color: ReverseFm}
|
||||
}
|
||||
|
||||
// Inverse is alias for the Reverse
|
||||
func Inverse(arg interface{}) Value {
|
||||
return Reverse(arg)
|
||||
}
|
||||
|
||||
// Conceal hides text, preserving an ability to select
|
||||
// the text and copy it. It is not widely supported (8).
|
||||
func Conceal(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Conceal()
|
||||
}
|
||||
return value{value: arg, color: ConcealFm}
|
||||
}
|
||||
|
||||
// Hidden is alias for the Conceal
|
||||
func Hidden(arg interface{}) Value {
|
||||
return Conceal(arg)
|
||||
}
|
||||
|
||||
// CrossedOut makes characters legible, but
|
||||
// marked for deletion (9).
|
||||
func CrossedOut(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.CrossedOut()
|
||||
}
|
||||
return value{value: arg, color: CrossedOutFm}
|
||||
}
|
||||
|
||||
// StrikeThrough is alias for the CrossedOut.
|
||||
func StrikeThrough(arg interface{}) Value {
|
||||
return CrossedOut(arg)
|
||||
}
|
||||
|
||||
// Framed (51).
|
||||
func Framed(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Framed()
|
||||
}
|
||||
return value{value: arg, color: FramedFm}
|
||||
}
|
||||
|
||||
// Encircled (52).
|
||||
func Encircled(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Encircled()
|
||||
}
|
||||
return value{value: arg, color: EncircledFm}
|
||||
}
|
||||
|
||||
// Overlined (53).
|
||||
func Overlined(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Overlined()
|
||||
}
|
||||
return value{value: arg, color: OverlinedFm}
|
||||
}
|
||||
|
||||
//
|
||||
// Foreground colors
|
||||
//
|
||||
//
|
||||
|
||||
// Black foreground color (30)
|
||||
func Black(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Black()
|
||||
}
|
||||
return value{value: arg, color: BlackFg}
|
||||
}
|
||||
|
||||
// Red foreground color (31)
|
||||
func Red(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Red()
|
||||
}
|
||||
return value{value: arg, color: RedFg}
|
||||
}
|
||||
|
||||
// Green foreground color (32)
|
||||
func Green(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Green()
|
||||
}
|
||||
return value{value: arg, color: GreenFg}
|
||||
}
|
||||
|
||||
// Yellow foreground color (33)
|
||||
func Yellow(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Yellow()
|
||||
}
|
||||
return value{value: arg, color: YellowFg}
|
||||
}
|
||||
|
||||
// Brown foreground color (33)
|
||||
//
|
||||
// Deprecated: use Yellow instead, following specification
|
||||
func Brown(arg interface{}) Value {
|
||||
return Yellow(arg)
|
||||
}
|
||||
|
||||
// Blue foreground color (34)
|
||||
func Blue(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Blue()
|
||||
}
|
||||
return value{value: arg, color: BlueFg}
|
||||
}
|
||||
|
||||
// Magenta foreground color (35)
|
||||
func Magenta(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Magenta()
|
||||
}
|
||||
return value{value: arg, color: MagentaFg}
|
||||
}
|
||||
|
||||
// Cyan foreground color (36)
|
||||
func Cyan(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Cyan()
|
||||
}
|
||||
return value{value: arg, color: CyanFg}
|
||||
}
|
||||
|
||||
// White foreground color (37)
|
||||
func White(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.White()
|
||||
}
|
||||
return value{value: arg, color: WhiteFg}
|
||||
}
|
||||
|
||||
//
|
||||
// Bright foreground colors
|
||||
//
|
||||
|
||||
// BrightBlack foreground color (90)
|
||||
func BrightBlack(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightBlack()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | BlackFg}
|
||||
}
|
||||
|
||||
// BrightRed foreground color (91)
|
||||
func BrightRed(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightRed()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | RedFg}
|
||||
}
|
||||
|
||||
// BrightGreen foreground color (92)
|
||||
func BrightGreen(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightGreen()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | GreenFg}
|
||||
}
|
||||
|
||||
// BrightYellow foreground color (93)
|
||||
func BrightYellow(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightYellow()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | YellowFg}
|
||||
}
|
||||
|
||||
// BrightBlue foreground color (94)
|
||||
func BrightBlue(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightBlue()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | BlueFg}
|
||||
}
|
||||
|
||||
// BrightMagenta foreground color (95)
|
||||
func BrightMagenta(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightMagenta()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | MagentaFg}
|
||||
}
|
||||
|
||||
// BrightCyan foreground color (96)
|
||||
func BrightCyan(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightCyan()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | CyanFg}
|
||||
}
|
||||
|
||||
// BrightWhite foreground color (97)
|
||||
func BrightWhite(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BrightWhite()
|
||||
}
|
||||
return value{value: arg, color: BrightFg | WhiteFg}
|
||||
}
|
||||
|
||||
//
|
||||
// Other
|
||||
//
|
||||
|
||||
// Index of pre-defined 8-bit foreground color
|
||||
// from 0 to 255 (38;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 30–37 m)
|
||||
// 8- 15: high intensity colors (as in ESC [ 90–97 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
func Index(n uint8, arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Index(n)
|
||||
}
|
||||
return value{value: arg, color: (Color(n) << shiftFg) | flagFg}
|
||||
}
|
||||
|
||||
// Gray from 0 to 24.
|
||||
func Gray(n uint8, arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.Gray(n)
|
||||
}
|
||||
if n > 23 {
|
||||
n = 23
|
||||
}
|
||||
return value{value: arg, color: (Color(232+n) << shiftFg) | flagFg}
|
||||
}
|
||||
|
||||
//
|
||||
// Background colors
|
||||
//
|
||||
//
|
||||
|
||||
// BgBlack background color (40)
|
||||
func BgBlack(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBlack()
|
||||
}
|
||||
return value{value: arg, color: BlackBg}
|
||||
}
|
||||
|
||||
// BgRed background color (41)
|
||||
func BgRed(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgRed()
|
||||
}
|
||||
return value{value: arg, color: RedBg}
|
||||
}
|
||||
|
||||
// BgGreen background color (42)
|
||||
func BgGreen(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgGreen()
|
||||
}
|
||||
return value{value: arg, color: GreenBg}
|
||||
}
|
||||
|
||||
// BgYellow background color (43)
|
||||
func BgYellow(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgYellow()
|
||||
}
|
||||
return value{value: arg, color: YellowBg}
|
||||
}
|
||||
|
||||
// BgBrown background color (43)
|
||||
//
|
||||
// Deprecated: use BgYellow instead, following specification
|
||||
func BgBrown(arg interface{}) Value {
|
||||
return BgYellow(arg)
|
||||
}
|
||||
|
||||
// BgBlue background color (44)
|
||||
func BgBlue(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBlue()
|
||||
}
|
||||
return value{value: arg, color: BlueBg}
|
||||
}
|
||||
|
||||
// BgMagenta background color (45)
|
||||
func BgMagenta(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgMagenta()
|
||||
}
|
||||
return value{value: arg, color: MagentaBg}
|
||||
}
|
||||
|
||||
// BgCyan background color (46)
|
||||
func BgCyan(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgCyan()
|
||||
}
|
||||
return value{value: arg, color: CyanBg}
|
||||
}
|
||||
|
||||
// BgWhite background color (47)
|
||||
func BgWhite(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgWhite()
|
||||
}
|
||||
return value{value: arg, color: WhiteBg}
|
||||
}
|
||||
|
||||
//
|
||||
// Bright background colors
|
||||
//
|
||||
|
||||
// BgBrightBlack background color (100)
|
||||
func BgBrightBlack(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightBlack()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | BlackBg}
|
||||
}
|
||||
|
||||
// BgBrightRed background color (101)
|
||||
func BgBrightRed(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightRed()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | RedBg}
|
||||
}
|
||||
|
||||
// BgBrightGreen background color (102)
|
||||
func BgBrightGreen(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightGreen()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | GreenBg}
|
||||
}
|
||||
|
||||
// BgBrightYellow background color (103)
|
||||
func BgBrightYellow(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightYellow()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | YellowBg}
|
||||
}
|
||||
|
||||
// BgBrightBlue background color (104)
|
||||
func BgBrightBlue(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightBlue()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | BlueBg}
|
||||
}
|
||||
|
||||
// BgBrightMagenta background color (105)
|
||||
func BgBrightMagenta(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightMagenta()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | MagentaBg}
|
||||
}
|
||||
|
||||
// BgBrightCyan background color (106)
|
||||
func BgBrightCyan(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightCyan()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | CyanBg}
|
||||
}
|
||||
|
||||
// BgBrightWhite background color (107)
|
||||
func BgBrightWhite(arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgBrightWhite()
|
||||
}
|
||||
return value{value: arg, color: BrightBg | WhiteBg}
|
||||
}
|
||||
|
||||
//
|
||||
// Other
|
||||
//
|
||||
|
||||
// BgIndex of 8-bit pre-defined background color
|
||||
// from 0 to 255 (48;5;n).
|
||||
//
|
||||
// 0- 7: standard colors (as in ESC [ 40–47 m)
|
||||
// 8- 15: high intensity colors (as in ESC [100–107 m)
|
||||
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
// 232-255: grayscale from black to white in 24 steps
|
||||
//
|
||||
func BgIndex(n uint8, arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgIndex(n)
|
||||
}
|
||||
return value{value: arg, color: (Color(n) << shiftBg) | flagBg}
|
||||
}
|
||||
|
||||
// BgGray from 0 to 24.
|
||||
func BgGray(n uint8, arg interface{}) Value {
|
||||
if val, ok := arg.(Value); ok {
|
||||
return val.BgGray(n)
|
||||
}
|
||||
if n > 23 {
|
||||
n = 23
|
||||
}
|
||||
return value{value: arg, color: (Color(n+232) << shiftBg) | flagBg}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/.cache/
|
||||
|
||||
/cmd/infocmp/infocmp
|
||||
/cmd/infocmp/.out/
|
||||
|
||||
/infocmp
|
||||
/.out/
|
||||
|
||||
*.txt
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Anmol Sethi
|
||||
|
||||
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,139 @@
|
|||
# About terminfo [![GoDoc][1]][2]
|
||||
|
||||
Package `terminfo` provides a pure-Go implementation of reading information
|
||||
from the terminfo database.
|
||||
|
||||
`terminfo` is meant as a replacement for `ncurses` in simple Go programs.
|
||||
|
||||
## Installing
|
||||
|
||||
Install in the usual Go way:
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/xo/terminfo
|
||||
```
|
||||
|
||||
## Using
|
||||
|
||||
Please see the [GoDoc API listing][2] for more information on using `terminfo`.
|
||||
|
||||
```go
|
||||
// _examples/simple/main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//r := rand.New(nil)
|
||||
|
||||
// load terminfo
|
||||
ti, err := terminfo.LoadFromEnv()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// cleanup
|
||||
defer func() {
|
||||
err := recover()
|
||||
termreset(ti)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
terminit(ti)
|
||||
termtitle(ti, "simple example!")
|
||||
termputs(ti, 3, 3, "Ctrl-C to exit")
|
||||
maxColors := termcolors(ti)
|
||||
if maxColors > 256 {
|
||||
maxColors = 256
|
||||
}
|
||||
for i := 0; i < maxColors; i++ {
|
||||
termputs(ti, 5+i/16, 5+i%16, ti.Colorf(i, 0, "█"))
|
||||
}
|
||||
|
||||
// wait for signal
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigs
|
||||
}
|
||||
|
||||
// terminit initializes the special CA mode on the terminal, and makes the
|
||||
// cursor invisible.
|
||||
func terminit(ti *terminfo.Terminfo) {
|
||||
buf := new(bytes.Buffer)
|
||||
// set the cursor invisible
|
||||
ti.Fprintf(buf, terminfo.CursorInvisible)
|
||||
// enter special mode
|
||||
ti.Fprintf(buf, terminfo.EnterCaMode)
|
||||
// clear the screen
|
||||
ti.Fprintf(buf, terminfo.ClearScreen)
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// termreset is the inverse of terminit.
|
||||
func termreset(ti *terminfo.Terminfo) {
|
||||
buf := new(bytes.Buffer)
|
||||
ti.Fprintf(buf, terminfo.ExitCaMode)
|
||||
ti.Fprintf(buf, terminfo.CursorNormal)
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// termputs puts a string at row, col, interpolating v.
|
||||
func termputs(ti *terminfo.Terminfo, row, col int, s string, v ...interface{}) {
|
||||
buf := new(bytes.Buffer)
|
||||
ti.Fprintf(buf, terminfo.CursorAddress, row, col)
|
||||
fmt.Fprintf(buf, s, v...)
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// sl is the status line terminfo.
|
||||
var sl *terminfo.Terminfo
|
||||
|
||||
// termtitle sets the window title.
|
||||
func termtitle(ti *terminfo.Terminfo, s string) {
|
||||
var once sync.Once
|
||||
once.Do(func() {
|
||||
if ti.Has(terminfo.HasStatusLine) {
|
||||
return
|
||||
}
|
||||
// load the sl xterm if terminal is an xterm or has COLORTERM
|
||||
if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") || os.Getenv("COLORTERM") == "truecolor" {
|
||||
sl, _ = terminfo.Load("xterm+sl")
|
||||
}
|
||||
})
|
||||
if sl != nil {
|
||||
ti = sl
|
||||
}
|
||||
if !ti.Has(terminfo.HasStatusLine) {
|
||||
return
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
ti.Fprintf(buf, terminfo.ToStatusLine)
|
||||
fmt.Fprint(buf, s)
|
||||
ti.Fprintf(buf, terminfo.FromStatusLine)
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// termcolors returns the maximum colors available for the terminal.
|
||||
func termcolors(ti *terminfo.Terminfo) int {
|
||||
if colors := ti.Num(terminfo.MaxColors); colors > 0 {
|
||||
return colors
|
||||
}
|
||||
return int(terminfo.ColorLevelBasic)
|
||||
}
|
||||
```
|
||||
|
||||
[1]: https://godoc.org/github.com/xo/terminfo?status.svg
|
||||
[2]: https://godoc.org/github.com/xo/terminfo
|
|
@ -0,0 +1,33 @@
|
|||
package terminfo
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// BoolCapName returns the bool capability name.
|
||||
func BoolCapName(i int) string {
|
||||
return boolCapNames[2*i]
|
||||
}
|
||||
|
||||
// BoolCapNameShort returns the short bool capability name.
|
||||
func BoolCapNameShort(i int) string {
|
||||
return boolCapNames[2*i+1]
|
||||
}
|
||||
|
||||
// NumCapName returns the num capability name.
|
||||
func NumCapName(i int) string {
|
||||
return numCapNames[2*i]
|
||||
}
|
||||
|
||||
// NumCapNameShort returns the short num capability name.
|
||||
func NumCapNameShort(i int) string {
|
||||
return numCapNames[2*i+1]
|
||||
}
|
||||
|
||||
// StringCapName returns the string capability name.
|
||||
func StringCapName(i int) string {
|
||||
return stringCapNames[2*i]
|
||||
}
|
||||
|
||||
// StringCapNameShort returns the short string capability name.
|
||||
func StringCapNameShort(i int) string {
|
||||
return stringCapNames[2*i+1]
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package terminfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ColorLevel is the color level supported by a terminal.
|
||||
type ColorLevel uint
|
||||
|
||||
// ColorLevel values.
|
||||
const (
|
||||
ColorLevelNone ColorLevel = iota
|
||||
ColorLevelBasic
|
||||
ColorLevelHundreds
|
||||
ColorLevelMillions
|
||||
)
|
||||
|
||||
// String satisfies the Stringer interface.
|
||||
func (c ColorLevel) String() string {
|
||||
switch c {
|
||||
case ColorLevelBasic:
|
||||
return "basic"
|
||||
case ColorLevelHundreds:
|
||||
return "hundreds"
|
||||
case ColorLevelMillions:
|
||||
return "millions"
|
||||
}
|
||||
return "none"
|
||||
}
|
||||
|
||||
// ChromaFormatterName returns the github.com/alecthomas/chroma compatible
|
||||
// formatter name for the color level.
|
||||
func (c ColorLevel) ChromaFormatterName() string {
|
||||
switch c {
|
||||
case ColorLevelBasic:
|
||||
return "terminal"
|
||||
case ColorLevelHundreds:
|
||||
return "terminal256"
|
||||
case ColorLevelMillions:
|
||||
return "terminal16m"
|
||||
}
|
||||
return "noop"
|
||||
}
|
||||
|
||||
// ColorLevelFromEnv returns the color level COLORTERM, FORCE_COLOR,
|
||||
// TERM_PROGRAM, or determined from the TERM environment variable.
|
||||
func ColorLevelFromEnv() (ColorLevel, error) {
|
||||
// check for overriding environment variables
|
||||
colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
|
||||
switch {
|
||||
case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit") || termProg == "Hyper":
|
||||
return ColorLevelMillions, nil
|
||||
case colorTerm != "" || forceColor != "":
|
||||
return ColorLevelBasic, nil
|
||||
case termProg == "Apple_Terminal":
|
||||
return ColorLevelHundreds, nil
|
||||
case termProg == "iTerm.app":
|
||||
ver := os.Getenv("TERM_PROGRAM_VERSION")
|
||||
if ver == "" {
|
||||
return ColorLevelHundreds, nil
|
||||
}
|
||||
i, err := strconv.Atoi(strings.Split(ver, ".")[0])
|
||||
if err != nil {
|
||||
return ColorLevelNone, ErrInvalidTermProgramVersion
|
||||
}
|
||||
if i == 3 {
|
||||
return ColorLevelMillions, nil
|
||||
}
|
||||
return ColorLevelHundreds, nil
|
||||
}
|
||||
|
||||
// otherwise determine from TERM's max_colors capability
|
||||
if term := os.Getenv("TERM"); term != "" {
|
||||
ti, err := Load(term)
|
||||
if err != nil {
|
||||
return ColorLevelNone, err
|
||||
}
|
||||
|
||||
v, ok := ti.Nums[MaxColors]
|
||||
switch {
|
||||
case !ok || v <= 16:
|
||||
return ColorLevelNone, nil
|
||||
case ok && v >= 256:
|
||||
return ColorLevelHundreds, nil
|
||||
}
|
||||
}
|
||||
|
||||
return ColorLevelBasic, nil
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/xo/terminfo
|
||||
|
||||
go 1.15
|
|
@ -0,0 +1,72 @@
|
|||
package terminfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// termCache is the terminfo cache.
|
||||
var termCache = struct {
|
||||
db map[string]*Terminfo
|
||||
sync.RWMutex
|
||||
}{
|
||||
db: make(map[string]*Terminfo),
|
||||
}
|
||||
|
||||
// Load follows the behavior described in terminfo(5) to find correct the
|
||||
// terminfo file using the name, reads the file and then returns a Terminfo
|
||||
// struct that describes the file.
|
||||
func Load(name string) (*Terminfo, error) {
|
||||
if name == "" {
|
||||
return nil, ErrEmptyTermName
|
||||
}
|
||||
|
||||
termCache.RLock()
|
||||
ti, ok := termCache.db[name]
|
||||
termCache.RUnlock()
|
||||
|
||||
if ok {
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
var checkDirs []string
|
||||
|
||||
// check $TERMINFO
|
||||
if dir := os.Getenv("TERMINFO"); dir != "" {
|
||||
checkDirs = append(checkDirs, dir)
|
||||
}
|
||||
|
||||
// check $HOME/.terminfo
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
checkDirs = append(checkDirs, path.Join(u.HomeDir, ".terminfo"))
|
||||
|
||||
// check $TERMINFO_DIRS
|
||||
if dirs := os.Getenv("TERMINFO_DIRS"); dirs != "" {
|
||||
checkDirs = append(checkDirs, strings.Split(dirs, ":")...)
|
||||
}
|
||||
|
||||
// check fallback directories
|
||||
checkDirs = append(checkDirs, "/etc/terminfo", "/lib/terminfo", "/usr/share/terminfo")
|
||||
for _, dir := range checkDirs {
|
||||
ti, err = Open(dir, name)
|
||||
if err != nil && err != ErrFileNotFound && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
} else if err == nil {
|
||||
return ti, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrDatabaseDirectoryNotFound
|
||||
}
|
||||
|
||||
// LoadFromEnv loads the terminal info based on the name contained in
|
||||
// environment variable TERM.
|
||||
func LoadFromEnv() (*Terminfo, error) {
|
||||
return Load(os.Getenv("TERM"))
|
||||
}
|
|
@ -0,0 +1,490 @@
|
|||
package terminfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// parametizer represents the a scan state for a parameterized string.
|
||||
type parametizer struct {
|
||||
// z is the string to parameterize
|
||||
z []byte
|
||||
|
||||
// pos is the current position in s.
|
||||
pos int
|
||||
|
||||
// nest is the current nest level.
|
||||
nest int
|
||||
|
||||
// s is the variable stack.
|
||||
s stack
|
||||
|
||||
// skipElse keeps the state of skipping else.
|
||||
skipElse bool
|
||||
|
||||
// buf is the result buffer.
|
||||
buf *bytes.Buffer
|
||||
|
||||
// params are the parameters to interpolate.
|
||||
params [9]interface{}
|
||||
|
||||
// vars are dynamic variables.
|
||||
vars [26]interface{}
|
||||
}
|
||||
|
||||
// staticVars are the static, global variables.
|
||||
var staticVars = struct {
|
||||
vars [26]interface{}
|
||||
sync.Mutex
|
||||
}{}
|
||||
|
||||
var parametizerPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
p := new(parametizer)
|
||||
p.buf = bytes.NewBuffer(make([]byte, 0, 45))
|
||||
return p
|
||||
},
|
||||
}
|
||||
|
||||
// newParametizer returns a new initialized parametizer from the pool.
|
||||
func newParametizer(z []byte) *parametizer {
|
||||
p := parametizerPool.Get().(*parametizer)
|
||||
p.z = z
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// reset resets the parametizer.
|
||||
func (p *parametizer) reset() {
|
||||
p.pos, p.nest = 0, 0
|
||||
|
||||
p.s.reset()
|
||||
p.buf.Reset()
|
||||
|
||||
p.params, p.vars = [9]interface{}{}, [26]interface{}{}
|
||||
|
||||
parametizerPool.Put(p)
|
||||
}
|
||||
|
||||
// stateFn represents the state of the scanner as a function that returns the
|
||||
// next state.
|
||||
type stateFn func() stateFn
|
||||
|
||||
// exec executes the parameterizer, interpolating the supplied parameters.
|
||||
func (p *parametizer) exec() string {
|
||||
for state := p.scanTextFn; state != nil; {
|
||||
state = state()
|
||||
}
|
||||
return p.buf.String()
|
||||
}
|
||||
|
||||
// peek returns the next byte.
|
||||
func (p *parametizer) peek() (byte, error) {
|
||||
if p.pos >= len(p.z) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return p.z[p.pos], nil
|
||||
}
|
||||
|
||||
// writeFrom writes the characters from ppos to pos to the buffer.
|
||||
func (p *parametizer) writeFrom(ppos int) {
|
||||
if p.pos > ppos {
|
||||
// append remaining characters.
|
||||
p.buf.Write(p.z[ppos:p.pos])
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parametizer) scanTextFn() stateFn {
|
||||
ppos := p.pos
|
||||
for {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
p.writeFrom(ppos)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ch == '%' {
|
||||
p.writeFrom(ppos)
|
||||
p.pos++
|
||||
return p.scanCodeFn
|
||||
}
|
||||
|
||||
p.pos++
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parametizer) scanCodeFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch ch {
|
||||
case '%':
|
||||
p.buf.WriteByte('%')
|
||||
|
||||
case ':':
|
||||
// this character is used to avoid interpreting "%-" and "%+" as operators.
|
||||
// the next character is where the format really begins.
|
||||
p.pos++
|
||||
_, err = p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return p.scanFormatFn
|
||||
|
||||
case '#', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
|
||||
return p.scanFormatFn
|
||||
|
||||
case 'o':
|
||||
p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 8))
|
||||
|
||||
case 'd':
|
||||
p.buf.WriteString(strconv.Itoa(p.s.popInt()))
|
||||
|
||||
case 'x':
|
||||
p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 16))
|
||||
|
||||
case 'X':
|
||||
p.buf.WriteString(strings.ToUpper(strconv.FormatInt(int64(p.s.popInt()), 16)))
|
||||
|
||||
case 's':
|
||||
p.buf.WriteString(p.s.popString())
|
||||
|
||||
case 'c':
|
||||
p.buf.WriteByte(p.s.popByte())
|
||||
|
||||
case 'p':
|
||||
p.pos++
|
||||
return p.pushParamFn
|
||||
|
||||
case 'P':
|
||||
p.pos++
|
||||
return p.setDsVarFn
|
||||
|
||||
case 'g':
|
||||
p.pos++
|
||||
return p.getDsVarFn
|
||||
|
||||
case '\'':
|
||||
p.pos++
|
||||
ch, err = p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.s.push(ch)
|
||||
|
||||
// skip the '\''
|
||||
p.pos++
|
||||
|
||||
case '{':
|
||||
p.pos++
|
||||
return p.pushIntfn
|
||||
|
||||
case 'l':
|
||||
p.s.push(len(p.s.popString()))
|
||||
|
||||
case '+':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai + bi)
|
||||
|
||||
case '-':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai - bi)
|
||||
|
||||
case '*':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai * bi)
|
||||
|
||||
case '/':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
if bi != 0 {
|
||||
p.s.push(ai / bi)
|
||||
} else {
|
||||
p.s.push(0)
|
||||
}
|
||||
|
||||
case 'm':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
if bi != 0 {
|
||||
p.s.push(ai % bi)
|
||||
} else {
|
||||
p.s.push(0)
|
||||
}
|
||||
|
||||
case '&':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai & bi)
|
||||
|
||||
case '|':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai | bi)
|
||||
|
||||
case '^':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai ^ bi)
|
||||
|
||||
case '=':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai == bi)
|
||||
|
||||
case '>':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai > bi)
|
||||
|
||||
case '<':
|
||||
bi, ai := p.s.popInt(), p.s.popInt()
|
||||
p.s.push(ai < bi)
|
||||
|
||||
case 'A':
|
||||
bi, ai := p.s.popBool(), p.s.popBool()
|
||||
p.s.push(ai && bi)
|
||||
|
||||
case 'O':
|
||||
bi, ai := p.s.popBool(), p.s.popBool()
|
||||
p.s.push(ai || bi)
|
||||
|
||||
case '!':
|
||||
p.s.push(!p.s.popBool())
|
||||
|
||||
case '~':
|
||||
p.s.push(^p.s.popInt())
|
||||
|
||||
case 'i':
|
||||
for i := range p.params[:2] {
|
||||
if n, ok := p.params[i].(int); ok {
|
||||
p.params[i] = n + 1
|
||||
}
|
||||
}
|
||||
|
||||
case '?', ';':
|
||||
|
||||
case 't':
|
||||
return p.scanThenFn
|
||||
|
||||
case 'e':
|
||||
p.skipElse = true
|
||||
return p.skipTextFn
|
||||
}
|
||||
|
||||
p.pos++
|
||||
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) scanFormatFn() stateFn {
|
||||
// the character was already read, so no need to check the error.
|
||||
ch, _ := p.peek()
|
||||
|
||||
// 6 should be the maximum length of a format string, for example "%:-9.9d".
|
||||
f := []byte{'%', ch, 0, 0, 0, 0}
|
||||
|
||||
var err error
|
||||
|
||||
for {
|
||||
p.pos++
|
||||
ch, err = p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
f = append(f, ch)
|
||||
switch ch {
|
||||
case 'o', 'd', 'x', 'X':
|
||||
fmt.Fprintf(p.buf, string(f), p.s.popInt())
|
||||
break
|
||||
|
||||
case 's':
|
||||
fmt.Fprintf(p.buf, string(f), p.s.popString())
|
||||
break
|
||||
|
||||
case 'c':
|
||||
fmt.Fprintf(p.buf, string(f), p.s.popByte())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
p.pos++
|
||||
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) pushParamFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ai := int(ch - '1'); ai >= 0 && ai < len(p.params) {
|
||||
p.s.push(p.params[ai])
|
||||
} else {
|
||||
p.s.push(0)
|
||||
}
|
||||
|
||||
// skip the '}'
|
||||
p.pos++
|
||||
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) setDsVarFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
staticVars.Lock()
|
||||
staticVars.vars[int(ch-'A')] = p.s.pop()
|
||||
staticVars.Unlock()
|
||||
} else if ch >= 'a' && ch <= 'z' {
|
||||
p.vars[int(ch-'a')] = p.s.pop()
|
||||
}
|
||||
|
||||
p.pos++
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) getDsVarFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var a byte
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
a = 'A'
|
||||
} else if ch >= 'a' && ch <= 'z' {
|
||||
a = 'a'
|
||||
}
|
||||
|
||||
staticVars.Lock()
|
||||
p.s.push(staticVars.vars[int(ch-a)])
|
||||
staticVars.Unlock()
|
||||
|
||||
p.pos++
|
||||
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) pushIntfn() stateFn {
|
||||
var ai int
|
||||
for {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.pos++
|
||||
if ch < '0' || ch > '9' {
|
||||
p.s.push(ai)
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
ai = (ai * 10) + int(ch-'0')
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parametizer) scanThenFn() stateFn {
|
||||
p.pos++
|
||||
|
||||
if p.s.popBool() {
|
||||
return p.scanTextFn
|
||||
}
|
||||
|
||||
p.skipElse = false
|
||||
|
||||
return p.skipTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) skipTextFn() stateFn {
|
||||
for {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.pos++
|
||||
if ch == '%' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p.skipElse {
|
||||
return p.skipElseFn
|
||||
}
|
||||
|
||||
return p.skipThenFn
|
||||
}
|
||||
|
||||
func (p *parametizer) skipThenFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.pos++
|
||||
switch ch {
|
||||
case ';':
|
||||
if p.nest == 0 {
|
||||
return p.scanTextFn
|
||||
}
|
||||
p.nest--
|
||||
|
||||
case '?':
|
||||
p.nest++
|
||||
|
||||
case 'e':
|
||||
if p.nest == 0 {
|
||||
return p.scanTextFn
|
||||
}
|
||||
}
|
||||
|
||||
return p.skipTextFn
|
||||
}
|
||||
|
||||
func (p *parametizer) skipElseFn() stateFn {
|
||||
ch, err := p.peek()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.pos++
|
||||
switch ch {
|
||||
case ';':
|
||||
if p.nest == 0 {
|
||||
return p.scanTextFn
|
||||
}
|
||||
p.nest--
|
||||
|
||||
case '?':
|
||||
p.nest++
|
||||
}
|
||||
|
||||
return p.skipTextFn
|
||||
}
|
||||
|
||||
// Printf evaluates a parameterized terminfo value z, interpolating params.
|
||||
func Printf(z []byte, params ...interface{}) string {
|
||||
p := newParametizer(z)
|
||||
defer p.reset()
|
||||
|
||||
// make sure we always have 9 parameters -- makes it easier
|
||||
// later to skip checks and its faster
|
||||
for i := 0; i < len(p.params) && i < len(params); i++ {
|
||||
p.params[i] = params[i]
|
||||
}
|
||||
|
||||
return p.exec()
|
||||
}
|
||||
|
||||
// Fprintf evaluates a parameterized terminfo value z, interpolating params and
|
||||
// writing to w.
|
||||
func Fprintf(w io.Writer, z []byte, params ...interface{}) {
|
||||
w.Write([]byte(Printf(z, params...)))
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package terminfo
|
||||
|
||||
type stack []interface{}
|
||||
|
||||
func (s *stack) push(v interface{}) {
|
||||
*s = append(*s, v)
|
||||
}
|
||||
|
||||
func (s *stack) pop() interface{} {
|
||||
if len(*s) == 0 {
|
||||
return nil
|
||||
}
|
||||
v := (*s)[len(*s)-1]
|
||||
*s = (*s)[:len(*s)-1]
|
||||
return v
|
||||
}
|
||||
|
||||
func (s *stack) popInt() int {
|
||||
if i, ok := s.pop().(int); ok {
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *stack) popBool() bool {
|
||||
if b, ok := s.pop().(bool); ok {
|
||||
return b
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *stack) popByte() byte {
|
||||
if b, ok := s.pop().(byte); ok {
|
||||
return b
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *stack) popString() string {
|
||||
if a, ok := s.pop().(string); ok {
|
||||
return a
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *stack) reset() {
|
||||
*s = (*s)[:0]
|
||||
}
|
|
@ -0,0 +1,538 @@
|
|||
// Package terminfo implements reading terminfo files in pure go.
|
||||
package terminfo
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Error is a terminfo error.
|
||||
type Error string
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (err Error) Error() string {
|
||||
return string(err)
|
||||
}
|
||||
|
||||
const (
|
||||
// ErrInvalidFileSize is the invalid file size error.
|
||||
ErrInvalidFileSize Error = "invalid file size"
|
||||
|
||||
// ErrUnexpectedFileEnd is the unexpected file end error.
|
||||
ErrUnexpectedFileEnd Error = "unexpected file end"
|
||||
|
||||
// ErrInvalidStringTable is the invalid string table error.
|
||||
ErrInvalidStringTable Error = "invalid string table"
|
||||
|
||||
// ErrInvalidMagic is the invalid magic error.
|
||||
ErrInvalidMagic Error = "invalid magic"
|
||||
|
||||
// ErrInvalidHeader is the invalid header error.
|
||||
ErrInvalidHeader Error = "invalid header"
|
||||
|
||||
// ErrInvalidNames is the invalid names error.
|
||||
ErrInvalidNames Error = "invalid names"
|
||||
|
||||
// ErrInvalidExtendedHeader is the invalid extended header error.
|
||||
ErrInvalidExtendedHeader Error = "invalid extended header"
|
||||
|
||||
// ErrEmptyTermName is the empty term name error.
|
||||
ErrEmptyTermName Error = "empty term name"
|
||||
|
||||
// ErrDatabaseDirectoryNotFound is the database directory not found error.
|
||||
ErrDatabaseDirectoryNotFound Error = "database directory not found"
|
||||
|
||||
// ErrFileNotFound is the file not found error.
|
||||
ErrFileNotFound Error = "file not found"
|
||||
|
||||
// ErrInvalidTermProgramVersion is the invalid TERM_PROGRAM_VERSION error.
|
||||
ErrInvalidTermProgramVersion Error = "invalid TERM_PROGRAM_VERSION"
|
||||
)
|
||||
|
||||
// Terminfo describes a terminal's capabilities.
|
||||
type Terminfo struct {
|
||||
// File is the original source file.
|
||||
File string
|
||||
|
||||
// Names are the provided cap names.
|
||||
Names []string
|
||||
|
||||
// Bools are the bool capabilities.
|
||||
Bools map[int]bool
|
||||
|
||||
// BoolsM are the missing bool capabilities.
|
||||
BoolsM map[int]bool
|
||||
|
||||
// Nums are the num capabilities.
|
||||
Nums map[int]int
|
||||
|
||||
// NumsM are the missing num capabilities.
|
||||
NumsM map[int]bool
|
||||
|
||||
// Strings are the string capabilities.
|
||||
Strings map[int][]byte
|
||||
|
||||
// StringsM are the missing string capabilities.
|
||||
StringsM map[int]bool
|
||||
|
||||
// ExtBools are the extended bool capabilities.
|
||||
ExtBools map[int]bool
|
||||
|
||||
// ExtBoolsNames is the map of extended bool capabilities to their index.
|
||||
ExtBoolNames map[int][]byte
|
||||
|
||||
// ExtNums are the extended num capabilities.
|
||||
ExtNums map[int]int
|
||||
|
||||
// ExtNumsNames is the map of extended num capabilities to their index.
|
||||
ExtNumNames map[int][]byte
|
||||
|
||||
// ExtStrings are the extended string capabilities.
|
||||
ExtStrings map[int][]byte
|
||||
|
||||
// ExtStringsNames is the map of extended string capabilities to their index.
|
||||
ExtStringNames map[int][]byte
|
||||
}
|
||||
|
||||
// Decode decodes the terminfo data contained in buf.
|
||||
func Decode(buf []byte) (*Terminfo, error) {
|
||||
var err error
|
||||
|
||||
// check max file length
|
||||
if len(buf) >= maxFileLength {
|
||||
return nil, ErrInvalidFileSize
|
||||
}
|
||||
|
||||
d := &decoder{
|
||||
buf: buf,
|
||||
len: len(buf),
|
||||
}
|
||||
|
||||
// read header
|
||||
h, err := d.readInts(6, 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var numWidth int
|
||||
|
||||
// check magic
|
||||
if h[fieldMagic] == magic {
|
||||
numWidth = 16
|
||||
} else if h[fieldMagic] == magicExtended {
|
||||
numWidth = 32
|
||||
} else {
|
||||
return nil, ErrInvalidMagic
|
||||
}
|
||||
|
||||
// check header
|
||||
if hasInvalidCaps(h) {
|
||||
return nil, ErrInvalidHeader
|
||||
}
|
||||
|
||||
// check remaining length
|
||||
if d.len-d.pos < capLength(h) {
|
||||
return nil, ErrUnexpectedFileEnd
|
||||
}
|
||||
|
||||
// read names
|
||||
names, err := d.readBytes(h[fieldNameSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check name is terminated properly
|
||||
i := findNull(names, 0)
|
||||
if i == -1 {
|
||||
return nil, ErrInvalidNames
|
||||
}
|
||||
names = names[:i]
|
||||
|
||||
// read bool caps
|
||||
bools, boolsM, err := d.readBools(h[fieldBoolCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read num caps
|
||||
nums, numsM, err := d.readNums(h[fieldNumCount], numWidth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read string caps
|
||||
strs, strsM, err := d.readStrings(h[fieldStringCount], h[fieldTableSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ti := &Terminfo{
|
||||
Names: strings.Split(string(names), "|"),
|
||||
Bools: bools,
|
||||
BoolsM: boolsM,
|
||||
Nums: nums,
|
||||
NumsM: numsM,
|
||||
Strings: strs,
|
||||
StringsM: strsM,
|
||||
}
|
||||
|
||||
// at the end of file, so no extended caps
|
||||
if d.pos >= d.len {
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// decode extended header
|
||||
eh, err := d.readInts(5, 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check extended offset field
|
||||
if hasInvalidExtOffset(eh) {
|
||||
return nil, ErrInvalidExtendedHeader
|
||||
}
|
||||
|
||||
// check extended cap lengths
|
||||
if d.len-d.pos != extCapLength(eh, numWidth) {
|
||||
return nil, ErrInvalidExtendedHeader
|
||||
}
|
||||
|
||||
// read extended bool caps
|
||||
ti.ExtBools, _, err = d.readBools(eh[fieldExtBoolCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read extended num caps
|
||||
ti.ExtNums, _, err = d.readNums(eh[fieldExtNumCount], numWidth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read extended string data table indexes
|
||||
extIndexes, err := d.readInts(eh[fieldExtOffsetCount], 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read string data table
|
||||
extData, err := d.readBytes(eh[fieldExtTableSize])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// precautionary check that exactly at end of file
|
||||
if d.pos != d.len {
|
||||
return nil, ErrUnexpectedFileEnd
|
||||
}
|
||||
|
||||
var last int
|
||||
// read extended string caps
|
||||
ti.ExtStrings, last, err = readStrings(extIndexes, extData, eh[fieldExtStringCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extIndexes, extData = extIndexes[eh[fieldExtStringCount]:], extData[last:]
|
||||
|
||||
// read extended bool names
|
||||
ti.ExtBoolNames, _, err = readStrings(extIndexes, extData, eh[fieldExtBoolCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extIndexes = extIndexes[eh[fieldExtBoolCount]:]
|
||||
|
||||
// read extended num names
|
||||
ti.ExtNumNames, _, err = readStrings(extIndexes, extData, eh[fieldExtNumCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extIndexes = extIndexes[eh[fieldExtNumCount]:]
|
||||
|
||||
// read extended string names
|
||||
ti.ExtStringNames, _, err = readStrings(extIndexes, extData, eh[fieldExtStringCount])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//extIndexes = extIndexes[eh[fieldExtStringCount]:]
|
||||
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// Open reads the terminfo file name from the specified directory dir.
|
||||
func Open(dir, name string) (*Terminfo, error) {
|
||||
var err error
|
||||
var buf []byte
|
||||
var filename string
|
||||
for _, f := range []string{
|
||||
path.Join(dir, name[0:1], name),
|
||||
path.Join(dir, strconv.FormatUint(uint64(name[0]), 16), name),
|
||||
} {
|
||||
buf, err = ioutil.ReadFile(f)
|
||||
if err == nil {
|
||||
filename = f
|
||||
break
|
||||
}
|
||||
}
|
||||
if buf == nil {
|
||||
return nil, ErrFileNotFound
|
||||
}
|
||||
|
||||
// decode
|
||||
ti, err := Decode(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// save original file name
|
||||
ti.File = filename
|
||||
|
||||
// add to cache
|
||||
termCache.Lock()
|
||||
for _, n := range ti.Names {
|
||||
termCache.db[n] = ti
|
||||
}
|
||||
termCache.Unlock()
|
||||
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// boolCaps returns all bool and extended capabilities using f to format the
|
||||
// index key.
|
||||
func (ti *Terminfo) boolCaps(f func(int) string, extended bool) map[string]bool {
|
||||
m := make(map[string]bool, len(ti.Bools)+len(ti.ExtBools))
|
||||
if !extended {
|
||||
for k, v := range ti.Bools {
|
||||
m[f(k)] = v
|
||||
}
|
||||
} else {
|
||||
for k, v := range ti.ExtBools {
|
||||
m[string(ti.ExtBoolNames[k])] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// BoolCaps returns all bool capabilities.
|
||||
func (ti *Terminfo) BoolCaps() map[string]bool {
|
||||
return ti.boolCaps(BoolCapName, false)
|
||||
}
|
||||
|
||||
// BoolCapsShort returns all bool capabilities, using the short name as the
|
||||
// index.
|
||||
func (ti *Terminfo) BoolCapsShort() map[string]bool {
|
||||
return ti.boolCaps(BoolCapNameShort, false)
|
||||
}
|
||||
|
||||
// ExtBoolCaps returns all extended bool capabilities.
|
||||
func (ti *Terminfo) ExtBoolCaps() map[string]bool {
|
||||
return ti.boolCaps(BoolCapName, true)
|
||||
}
|
||||
|
||||
// ExtBoolCapsShort returns all extended bool capabilities, using the short
|
||||
// name as the index.
|
||||
func (ti *Terminfo) ExtBoolCapsShort() map[string]bool {
|
||||
return ti.boolCaps(BoolCapNameShort, true)
|
||||
}
|
||||
|
||||
// numCaps returns all num and extended capabilities using f to format the
|
||||
// index key.
|
||||
func (ti *Terminfo) numCaps(f func(int) string, extended bool) map[string]int {
|
||||
m := make(map[string]int, len(ti.Nums)+len(ti.ExtNums))
|
||||
if !extended {
|
||||
for k, v := range ti.Nums {
|
||||
m[f(k)] = v
|
||||
}
|
||||
} else {
|
||||
for k, v := range ti.ExtNums {
|
||||
m[string(ti.ExtNumNames[k])] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// NumCaps returns all num capabilities.
|
||||
func (ti *Terminfo) NumCaps() map[string]int {
|
||||
return ti.numCaps(NumCapName, false)
|
||||
}
|
||||
|
||||
// NumCapsShort returns all num capabilities, using the short name as the
|
||||
// index.
|
||||
func (ti *Terminfo) NumCapsShort() map[string]int {
|
||||
return ti.numCaps(NumCapNameShort, false)
|
||||
}
|
||||
|
||||
// ExtNumCaps returns all extended num capabilities.
|
||||
func (ti *Terminfo) ExtNumCaps() map[string]int {
|
||||
return ti.numCaps(NumCapName, true)
|
||||
}
|
||||
|
||||
// ExtNumCapsShort returns all extended num capabilities, using the short
|
||||
// name as the index.
|
||||
func (ti *Terminfo) ExtNumCapsShort() map[string]int {
|
||||
return ti.numCaps(NumCapNameShort, true)
|
||||
}
|
||||
|
||||
// stringCaps returns all string and extended capabilities using f to format the
|
||||
// index key.
|
||||
func (ti *Terminfo) stringCaps(f func(int) string, extended bool) map[string][]byte {
|
||||
m := make(map[string][]byte, len(ti.Strings)+len(ti.ExtStrings))
|
||||
if !extended {
|
||||
for k, v := range ti.Strings {
|
||||
m[f(k)] = v
|
||||
}
|
||||
} else {
|
||||
for k, v := range ti.ExtStrings {
|
||||
m[string(ti.ExtStringNames[k])] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// StringCaps returns all string capabilities.
|
||||
func (ti *Terminfo) StringCaps() map[string][]byte {
|
||||
return ti.stringCaps(StringCapName, false)
|
||||
}
|
||||
|
||||
// StringCapsShort returns all string capabilities, using the short name as the
|
||||
// index.
|
||||
func (ti *Terminfo) StringCapsShort() map[string][]byte {
|
||||
return ti.stringCaps(StringCapNameShort, false)
|
||||
}
|
||||
|
||||
// ExtStringCaps returns all extended string capabilities.
|
||||
func (ti *Terminfo) ExtStringCaps() map[string][]byte {
|
||||
return ti.stringCaps(StringCapName, true)
|
||||
}
|
||||
|
||||
// ExtStringCapsShort returns all extended string capabilities, using the short
|
||||
// name as the index.
|
||||
func (ti *Terminfo) ExtStringCapsShort() map[string][]byte {
|
||||
return ti.stringCaps(StringCapNameShort, true)
|
||||
}
|
||||
|
||||
// Has determines if the bool cap i is present.
|
||||
func (ti *Terminfo) Has(i int) bool {
|
||||
return ti.Bools[i]
|
||||
}
|
||||
|
||||
// Num returns the num cap i, or -1 if not present.
|
||||
func (ti *Terminfo) Num(i int) int {
|
||||
n, ok := ti.Nums[i]
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Printf formats the string cap i, interpolating parameters v.
|
||||
func (ti *Terminfo) Printf(i int, v ...interface{}) string {
|
||||
return Printf(ti.Strings[i], v...)
|
||||
}
|
||||
|
||||
// Fprintf prints the string cap i to writer w, interpolating parameters v.
|
||||
func (ti *Terminfo) Fprintf(w io.Writer, i int, v ...interface{}) {
|
||||
Fprintf(w, ti.Strings[i], v...)
|
||||
}
|
||||
|
||||
// Color takes a foreground and background color and returns string that sets
|
||||
// them for this terminal.
|
||||
func (ti *Terminfo) Colorf(fg, bg int, str string) string {
|
||||
maxColors := int(ti.Nums[MaxColors])
|
||||
|
||||
// map bright colors to lower versions if the color table only holds 8.
|
||||
if maxColors == 8 {
|
||||
if fg > 7 && fg < 16 {
|
||||
fg -= 8
|
||||
}
|
||||
if bg > 7 && bg < 16 {
|
||||
bg -= 8
|
||||
}
|
||||
}
|
||||
|
||||
var s string
|
||||
if maxColors > fg && fg >= 0 {
|
||||
s += ti.Printf(SetAForeground, fg)
|
||||
}
|
||||
if maxColors > bg && bg >= 0 {
|
||||
s += ti.Printf(SetABackground, bg)
|
||||
}
|
||||
return s + str + ti.Printf(ExitAttributeMode)
|
||||
}
|
||||
|
||||
// Goto returns a string suitable for addressing the cursor at the given
|
||||
// row and column. The origin 0, 0 is in the upper left corner of the screen.
|
||||
func (ti *Terminfo) Goto(row, col int) string {
|
||||
return Printf(ti.Strings[CursorAddress], row, col)
|
||||
}
|
||||
|
||||
// Puts emits the string to the writer, but expands inline padding indications
|
||||
// (of the form $<[delay]> where [delay] is msec) to a suitable number of
|
||||
// padding characters (usually null bytes) based upon the supplied baud. At
|
||||
// high baud rates, more padding characters will be inserted.
|
||||
/*func (ti *Terminfo) Puts(w io.Writer, s string, lines, baud int) (int, error) {
|
||||
var err error
|
||||
for {
|
||||
start := strings.Index(s, "$<")
|
||||
if start == -1 {
|
||||
// most strings don't need padding, which is good news!
|
||||
return io.WriteString(w, s)
|
||||
}
|
||||
|
||||
end := strings.Index(s, ">")
|
||||
if end == -1 {
|
||||
// unterminated... just emit bytes unadulterated.
|
||||
return io.WriteString(w, "$<"+s)
|
||||
}
|
||||
|
||||
var c int
|
||||
c, err = io.WriteString(w, s[:start])
|
||||
if err != nil {
|
||||
return n + c, err
|
||||
}
|
||||
n += c
|
||||
|
||||
s = s[start+2:]
|
||||
val := s[:end]
|
||||
s = s[end+1:]
|
||||
var ms int
|
||||
var dot, mandatory, asterisk bool
|
||||
unit := 1000
|
||||
for _, ch := range val {
|
||||
switch {
|
||||
case ch >= '0' && ch <= '9':
|
||||
ms = (ms * 10) + int(ch-'0')
|
||||
if dot {
|
||||
unit *= 10
|
||||
}
|
||||
case ch == '.' && !dot:
|
||||
dot = true
|
||||
case ch == '*' && !asterisk:
|
||||
ms *= lines
|
||||
asterisk = true
|
||||
case ch == '/':
|
||||
mandatory = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
z, pad := ((baud/8)/unit)*ms, ti.Strings[PadChar]
|
||||
b := make([]byte, len(pad)*z)
|
||||
for bp := copy(b, pad); bp < len(b); bp *= 2 {
|
||||
copy(b[bp:], b[:bp])
|
||||
}
|
||||
|
||||
if (!ti.Bools[XonXoff] && baud > int(ti.Nums[PaddingBaudRate])) || mandatory {
|
||||
c, err = w.Write(b)
|
||||
if err != nil {
|
||||
return n + c, err
|
||||
}
|
||||
n += c
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}*/
|
|
@ -0,0 +1,266 @@
|
|||
package terminfo
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxFileLength is the max file length.
|
||||
maxFileLength = 4096
|
||||
|
||||
// magic is the file magic for terminfo files.
|
||||
magic = 0432
|
||||
|
||||
// magicExtended is the file magic for terminfo files with the extended number format.
|
||||
magicExtended = 01036
|
||||
)
|
||||
|
||||
// header fields.
|
||||
const (
|
||||
fieldMagic = iota
|
||||
fieldNameSize
|
||||
fieldBoolCount
|
||||
fieldNumCount
|
||||
fieldStringCount
|
||||
fieldTableSize
|
||||
)
|
||||
|
||||
// header extended fields.
|
||||
const (
|
||||
fieldExtBoolCount = iota
|
||||
fieldExtNumCount
|
||||
fieldExtStringCount
|
||||
fieldExtOffsetCount
|
||||
fieldExtTableSize
|
||||
)
|
||||
|
||||
// hasInvalidCaps determines if the capabilities in h are invalid.
|
||||
func hasInvalidCaps(h []int) bool {
|
||||
return h[fieldBoolCount] > CapCountBool ||
|
||||
h[fieldNumCount] > CapCountNum ||
|
||||
h[fieldStringCount] > CapCountString
|
||||
}
|
||||
|
||||
// capLength returns the total length of the capabilities in bytes.
|
||||
func capLength(h []int) int {
|
||||
return h[fieldNameSize] +
|
||||
h[fieldBoolCount] +
|
||||
(h[fieldNameSize]+h[fieldBoolCount])%2 + // account for word align
|
||||
h[fieldNumCount]*2 +
|
||||
h[fieldStringCount]*2 +
|
||||
h[fieldTableSize]
|
||||
}
|
||||
|
||||
// hasInvalidExtOffset determines if the extended offset field is valid.
|
||||
func hasInvalidExtOffset(h []int) bool {
|
||||
return h[fieldExtBoolCount]+
|
||||
h[fieldExtNumCount]+
|
||||
h[fieldExtStringCount]*2 != h[fieldExtOffsetCount]
|
||||
}
|
||||
|
||||
// extCapLength returns the total length of extended capabilities in bytes.
|
||||
func extCapLength(h []int, numWidth int) int {
|
||||
return h[fieldExtBoolCount] +
|
||||
h[fieldExtBoolCount]%2 + // account for word align
|
||||
h[fieldExtNumCount]*(numWidth/8) +
|
||||
h[fieldExtOffsetCount]*2 +
|
||||
h[fieldExtTableSize]
|
||||
}
|
||||
|
||||
// findNull finds the position of null in buf.
|
||||
func findNull(buf []byte, i int) int {
|
||||
for ; i < len(buf); i++ {
|
||||
if buf[i] == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// readStrings decodes n strings from string data table buf using the indexes in idx.
|
||||
func readStrings(idx []int, buf []byte, n int) (map[int][]byte, int, error) {
|
||||
var last int
|
||||
m := make(map[int][]byte)
|
||||
for i := 0; i < n; i++ {
|
||||
start := idx[i]
|
||||
if start < 0 {
|
||||
continue
|
||||
}
|
||||
if end := findNull(buf, start); end != -1 {
|
||||
m[i], last = buf[start:end], end+1
|
||||
} else {
|
||||
return nil, 0, ErrInvalidStringTable
|
||||
}
|
||||
}
|
||||
return m, last, nil
|
||||
}
|
||||
|
||||
// decoder holds state info while decoding a terminfo file.
|
||||
type decoder struct {
|
||||
buf []byte
|
||||
pos int
|
||||
len int
|
||||
}
|
||||
|
||||
// readBytes reads the next n bytes of buf, incrementing pos by n.
|
||||
func (d *decoder) readBytes(n int) ([]byte, error) {
|
||||
if d.len < d.pos+n {
|
||||
return nil, ErrUnexpectedFileEnd
|
||||
}
|
||||
n, d.pos = d.pos, d.pos+n
|
||||
return d.buf[n:d.pos], nil
|
||||
}
|
||||
|
||||
// readInts reads n number of ints with width w.
|
||||
func (d *decoder) readInts(n, w int) ([]int, error) {
|
||||
w /= 8
|
||||
l := n * w
|
||||
|
||||
buf, err := d.readBytes(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// align
|
||||
d.pos += d.pos % 2
|
||||
|
||||
z := make([]int, n)
|
||||
for i, j := 0, 0; i < l; i, j = i+w, j+1 {
|
||||
switch w {
|
||||
case 1:
|
||||
z[i] = int(buf[i])
|
||||
case 2:
|
||||
z[j] = int(int16(buf[i+1])<<8 | int16(buf[i]))
|
||||
case 4:
|
||||
z[j] = int(buf[i+3])<<24 | int(buf[i+2])<<16 | int(buf[i+1])<<8 | int(buf[i])
|
||||
}
|
||||
}
|
||||
|
||||
return z, nil
|
||||
}
|
||||
|
||||
// readBools reads the next n bools.
|
||||
func (d *decoder) readBools(n int) (map[int]bool, map[int]bool, error) {
|
||||
buf, err := d.readInts(n, 8)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// process
|
||||
bools, boolsM := make(map[int]bool), make(map[int]bool)
|
||||
for i, b := range buf {
|
||||
bools[i] = b == 1
|
||||
if int8(b) == -2 {
|
||||
boolsM[i] = true
|
||||
}
|
||||
}
|
||||
|
||||
return bools, boolsM, nil
|
||||
}
|
||||
|
||||
// readNums reads the next n nums.
|
||||
func (d *decoder) readNums(n, w int) (map[int]int, map[int]bool, error) {
|
||||
buf, err := d.readInts(n, w)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// process
|
||||
nums, numsM := make(map[int]int), make(map[int]bool)
|
||||
for i := 0; i < n; i++ {
|
||||
nums[i] = buf[i]
|
||||
if buf[i] == -2 {
|
||||
numsM[i] = true
|
||||
}
|
||||
}
|
||||
|
||||
return nums, numsM, nil
|
||||
}
|
||||
|
||||
// readStringTable reads the string data for n strings and the accompanying data
|
||||
// table of length sz.
|
||||
func (d *decoder) readStringTable(n, sz int) ([][]byte, []int, error) {
|
||||
buf, err := d.readInts(n, 16)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// read string data table
|
||||
data, err := d.readBytes(sz)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// align
|
||||
d.pos += d.pos % 2
|
||||
|
||||
// process
|
||||
s := make([][]byte, n)
|
||||
var m []int
|
||||
for i := 0; i < n; i++ {
|
||||
start := buf[i]
|
||||
if start == -2 {
|
||||
m = append(m, i)
|
||||
} else if start >= 0 {
|
||||
if end := findNull(data, start); end != -1 {
|
||||
s[i] = data[start:end]
|
||||
} else {
|
||||
return nil, nil, ErrInvalidStringTable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s, m, nil
|
||||
}
|
||||
|
||||
// readStrings reads the next n strings and processes the string data table of
|
||||
// length sz.
|
||||
func (d *decoder) readStrings(n, sz int) (map[int][]byte, map[int]bool, error) {
|
||||
s, m, err := d.readStringTable(n, sz)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
strs := make(map[int][]byte)
|
||||
for k, v := range s {
|
||||
if k == AcsChars {
|
||||
v = canonicalizeAscChars(v)
|
||||
}
|
||||
strs[k] = v
|
||||
}
|
||||
|
||||
strsM := make(map[int]bool, len(m))
|
||||
for _, k := range m {
|
||||
strsM[k] = true
|
||||
}
|
||||
|
||||
return strs, strsM, nil
|
||||
}
|
||||
|
||||
// canonicalizeAscChars reorders chars to be unique, in order.
|
||||
//
|
||||
// see repair_ascc in ncurses-6.0/progs/dump_entry.c
|
||||
func canonicalizeAscChars(z []byte) []byte {
|
||||
var c chars
|
||||
enc := make(map[byte]byte, len(z)/2)
|
||||
for i := 0; i < len(z); i += 2 {
|
||||
if _, ok := enc[z[i]]; !ok {
|
||||
a, b := z[i], z[i+1]
|
||||
//log.Printf(">>> a: %d %c, b: %d %c", a, a, b, b)
|
||||
c, enc[a] = append(c, b), b
|
||||
}
|
||||
}
|
||||
sort.Sort(c)
|
||||
|
||||
r := make([]byte, 2*len(c))
|
||||
for i := 0; i < len(c); i++ {
|
||||
r[i*2], r[i*2+1] = c[i], enc[c[i]]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type chars []byte
|
||||
|
||||
func (c chars) Len() int { return len(c) }
|
||||
func (c chars) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
func (c chars) Less(i, j int) bool { return c[i] < c[j] }
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
// +build gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
|
|
@ -39,20 +39,25 @@ func (bigEndian) Uint64(b []byte) uint64 {
|
|||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
// hostByteOrder returns binary.LittleEndian on little-endian machines and
|
||||
// binary.BigEndian on big-endian machines.
|
||||
// hostByteOrder returns littleEndian on little-endian machines and
|
||||
// bigEndian on big-endian machines.
|
||||
func hostByteOrder() byteOrder {
|
||||
switch runtime.GOARCH {
|
||||
case "386", "amd64", "amd64p32",
|
||||
"alpha",
|
||||
"arm", "arm64",
|
||||
"mipsle", "mips64le", "mips64p32le",
|
||||
"nios2",
|
||||
"ppc64le",
|
||||
"riscv", "riscv64":
|
||||
"riscv", "riscv64",
|
||||
"sh":
|
||||
return littleEndian{}
|
||||
case "armbe", "arm64be",
|
||||
"m68k",
|
||||
"mips", "mips64", "mips64p32",
|
||||
"ppc", "ppc64",
|
||||
"s390", "s390x",
|
||||
"shbe",
|
||||
"sparc", "sparc64":
|
||||
return bigEndian{}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
// various CPU architectures.
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Initialized reports whether the CPU features were initialized.
|
||||
//
|
||||
// For some GOOS/GOARCH combinations initialization of the CPU features depends
|
||||
|
@ -24,26 +29,46 @@ type CacheLinePad struct{ _ [cacheLineSize]byte }
|
|||
// and HasAVX2 are only set if the OS supports XMM and YMM
|
||||
// registers in addition to the CPUID feature bit being set.
|
||||
var X86 struct {
|
||||
_ CacheLinePad
|
||||
HasAES bool // AES hardware implementation (AES NI)
|
||||
HasADX bool // Multi-precision add-carry instruction extensions
|
||||
HasAVX bool // Advanced vector extension
|
||||
HasAVX2 bool // Advanced vector extension 2
|
||||
HasBMI1 bool // Bit manipulation instruction set 1
|
||||
HasBMI2 bool // Bit manipulation instruction set 2
|
||||
HasERMS bool // Enhanced REP for MOVSB and STOSB
|
||||
HasFMA bool // Fused-multiply-add instructions
|
||||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
||||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
|
||||
HasPOPCNT bool // Hamming weight instruction POPCNT.
|
||||
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
|
||||
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
|
||||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
|
||||
HasSSE3 bool // Streaming SIMD extension 3
|
||||
HasSSSE3 bool // Supplemental streaming SIMD extension 3
|
||||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
|
||||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
|
||||
_ CacheLinePad
|
||||
_ CacheLinePad
|
||||
HasAES bool // AES hardware implementation (AES NI)
|
||||
HasADX bool // Multi-precision add-carry instruction extensions
|
||||
HasAVX bool // Advanced vector extension
|
||||
HasAVX2 bool // Advanced vector extension 2
|
||||
HasAVX512 bool // Advanced vector extension 512
|
||||
HasAVX512F bool // Advanced vector extension 512 Foundation Instructions
|
||||
HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions
|
||||
HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions
|
||||
HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions
|
||||
HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions
|
||||
HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions
|
||||
HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions
|
||||
HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add
|
||||
HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions
|
||||
HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision
|
||||
HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision
|
||||
HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions
|
||||
HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations
|
||||
HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions
|
||||
HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions
|
||||
HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions
|
||||
HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2
|
||||
HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms
|
||||
HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions
|
||||
HasBMI1 bool // Bit manipulation instruction set 1
|
||||
HasBMI2 bool // Bit manipulation instruction set 2
|
||||
HasERMS bool // Enhanced REP for MOVSB and STOSB
|
||||
HasFMA bool // Fused-multiply-add instructions
|
||||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
||||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
|
||||
HasPOPCNT bool // Hamming weight instruction POPCNT.
|
||||
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
|
||||
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
|
||||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
|
||||
HasSSE3 bool // Streaming SIMD extension 3
|
||||
HasSSSE3 bool // Supplemental streaming SIMD extension 3
|
||||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
|
||||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// ARM64 contains the supported CPU features of the
|
||||
|
@ -169,3 +194,94 @@ var S390X struct {
|
|||
HasVXE bool // vector-enhancements facility 1
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
func init() {
|
||||
archInit()
|
||||
initOptions()
|
||||
processOptions()
|
||||
}
|
||||
|
||||
// options contains the cpu debug options that can be used in GODEBUG.
|
||||
// Options are arch dependent and are added by the arch specific initOptions functions.
|
||||
// Features that are mandatory for the specific GOARCH should have the Required field set
|
||||
// (e.g. SSE2 on amd64).
|
||||
var options []option
|
||||
|
||||
// Option names should be lower case. e.g. avx instead of AVX.
|
||||
type option struct {
|
||||
Name string
|
||||
Feature *bool
|
||||
Specified bool // whether feature value was specified in GODEBUG
|
||||
Enable bool // whether feature should be enabled
|
||||
Required bool // whether feature is mandatory and can not be disabled
|
||||
}
|
||||
|
||||
func processOptions() {
|
||||
env := os.Getenv("GODEBUG")
|
||||
field:
|
||||
for env != "" {
|
||||
field := ""
|
||||
i := strings.IndexByte(env, ',')
|
||||
if i < 0 {
|
||||
field, env = env, ""
|
||||
} else {
|
||||
field, env = env[:i], env[i+1:]
|
||||
}
|
||||
if len(field) < 4 || field[:4] != "cpu." {
|
||||
continue
|
||||
}
|
||||
i = strings.IndexByte(field, '=')
|
||||
if i < 0 {
|
||||
print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n")
|
||||
continue
|
||||
}
|
||||
key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
|
||||
|
||||
var enable bool
|
||||
switch value {
|
||||
case "on":
|
||||
enable = true
|
||||
case "off":
|
||||
enable = false
|
||||
default:
|
||||
print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
|
||||
continue field
|
||||
}
|
||||
|
||||
if key == "all" {
|
||||
for i := range options {
|
||||
options[i].Specified = true
|
||||
options[i].Enable = enable || options[i].Required
|
||||
}
|
||||
continue field
|
||||
}
|
||||
|
||||
for i := range options {
|
||||
if options[i].Name == key {
|
||||
options[i].Specified = true
|
||||
options[i].Enable = enable
|
||||
continue field
|
||||
}
|
||||
}
|
||||
|
||||
print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n")
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
if !o.Specified {
|
||||
continue
|
||||
}
|
||||
|
||||
if o.Enable && !*o.Feature {
|
||||
print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n")
|
||||
continue
|
||||
}
|
||||
|
||||
if !o.Enable && o.Required {
|
||||
print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n")
|
||||
continue
|
||||
}
|
||||
|
||||
*o.Feature = o.Enable
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix,ppc64
|
||||
//go:build aix
|
||||
// +build aix
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 128
|
||||
|
||||
const (
|
||||
// getsystemcfg constants
|
||||
_SC_IMPL = 2
|
||||
|
@ -15,7 +14,7 @@ const (
|
|||
_IMPL_POWER9 = 0x20000
|
||||
)
|
||||
|
||||
func init() {
|
||||
func archInit() {
|
||||
impl := getsystemcfg(_SC_IMPL)
|
||||
if impl&_IMPL_POWER8 != 0 {
|
||||
PPC64.IsPOWER8 = true
|
|
@ -38,3 +38,36 @@ const (
|
|||
hwcap2_SHA2 = 1 << 3
|
||||
hwcap2_CRC32 = 1 << 4
|
||||
)
|
||||
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "pmull", Feature: &ARM.HasPMULL},
|
||||
{Name: "sha1", Feature: &ARM.HasSHA1},
|
||||
{Name: "sha2", Feature: &ARM.HasSHA2},
|
||||
{Name: "swp", Feature: &ARM.HasSWP},
|
||||
{Name: "thumb", Feature: &ARM.HasTHUMB},
|
||||
{Name: "thumbee", Feature: &ARM.HasTHUMBEE},
|
||||
{Name: "tls", Feature: &ARM.HasTLS},
|
||||
{Name: "vfp", Feature: &ARM.HasVFP},
|
||||
{Name: "vfpd32", Feature: &ARM.HasVFPD32},
|
||||
{Name: "vfpv3", Feature: &ARM.HasVFPv3},
|
||||
{Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16},
|
||||
{Name: "vfpv4", Feature: &ARM.HasVFPv4},
|
||||
{Name: "half", Feature: &ARM.HasHALF},
|
||||
{Name: "26bit", Feature: &ARM.Has26BIT},
|
||||
{Name: "fastmul", Feature: &ARM.HasFASTMUL},
|
||||
{Name: "fpa", Feature: &ARM.HasFPA},
|
||||
{Name: "edsp", Feature: &ARM.HasEDSP},
|
||||
{Name: "java", Feature: &ARM.HasJAVA},
|
||||
{Name: "iwmmxt", Feature: &ARM.HasIWMMXT},
|
||||
{Name: "crunch", Feature: &ARM.HasCRUNCH},
|
||||
{Name: "neon", Feature: &ARM.HasNEON},
|
||||
{Name: "idivt", Feature: &ARM.HasIDIVT},
|
||||
{Name: "idiva", Feature: &ARM.HasIDIVA},
|
||||
{Name: "lpae", Feature: &ARM.HasLPAE},
|
||||
{Name: "evtstrm", Feature: &ARM.HasEVTSTRM},
|
||||
{Name: "aes", Feature: &ARM.HasAES},
|
||||
{Name: "crc32", Feature: &ARM.HasCRC32},
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,27 +8,65 @@ import "runtime"
|
|||
|
||||
const cacheLineSize = 64
|
||||
|
||||
func init() {
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "fp", Feature: &ARM64.HasFP},
|
||||
{Name: "asimd", Feature: &ARM64.HasASIMD},
|
||||
{Name: "evstrm", Feature: &ARM64.HasEVTSTRM},
|
||||
{Name: "aes", Feature: &ARM64.HasAES},
|
||||
{Name: "fphp", Feature: &ARM64.HasFPHP},
|
||||
{Name: "jscvt", Feature: &ARM64.HasJSCVT},
|
||||
{Name: "lrcpc", Feature: &ARM64.HasLRCPC},
|
||||
{Name: "pmull", Feature: &ARM64.HasPMULL},
|
||||
{Name: "sha1", Feature: &ARM64.HasSHA1},
|
||||
{Name: "sha2", Feature: &ARM64.HasSHA2},
|
||||
{Name: "sha3", Feature: &ARM64.HasSHA3},
|
||||
{Name: "sha512", Feature: &ARM64.HasSHA512},
|
||||
{Name: "sm3", Feature: &ARM64.HasSM3},
|
||||
{Name: "sm4", Feature: &ARM64.HasSM4},
|
||||
{Name: "sve", Feature: &ARM64.HasSVE},
|
||||
{Name: "crc32", Feature: &ARM64.HasCRC32},
|
||||
{Name: "atomics", Feature: &ARM64.HasATOMICS},
|
||||
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
|
||||
{Name: "cpuid", Feature: &ARM64.HasCPUID},
|
||||
{Name: "asimrdm", Feature: &ARM64.HasASIMDRDM},
|
||||
{Name: "fcma", Feature: &ARM64.HasFCMA},
|
||||
{Name: "dcpop", Feature: &ARM64.HasDCPOP},
|
||||
{Name: "asimddp", Feature: &ARM64.HasASIMDDP},
|
||||
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
|
||||
}
|
||||
}
|
||||
|
||||
func archInit() {
|
||||
switch runtime.GOOS {
|
||||
case "android", "darwin":
|
||||
// Android and iOS don't seem to allow reading these registers.
|
||||
// Fake the minimal features expected by
|
||||
// TestARM64minimalFeatures.
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
case "linux":
|
||||
case "freebsd":
|
||||
readARM64Registers()
|
||||
case "linux", "netbsd":
|
||||
doinit()
|
||||
default:
|
||||
readARM64Registers()
|
||||
// Most platforms don't seem to allow reading these registers.
|
||||
//
|
||||
// OpenBSD:
|
||||
// See https://golang.org/issue/31746
|
||||
setMinimalFeatures()
|
||||
}
|
||||
}
|
||||
|
||||
// setMinimalFeatures fakes the minimal ARM64 features expected by
|
||||
// TestARM64minimalFeatures.
|
||||
func setMinimalFeatures() {
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
}
|
||||
|
||||
func readARM64Registers() {
|
||||
Initialized = true
|
||||
|
||||
// ID_AA64ISAR0_EL1
|
||||
isar0 := getisar0()
|
||||
parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0())
|
||||
}
|
||||
|
||||
func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
|
||||
// ID_AA64ISAR0_EL1
|
||||
switch extractBits(isar0, 4, 7) {
|
||||
case 1:
|
||||
ARM64.HasAES = true
|
||||
|
@ -86,8 +124,6 @@ func readARM64Registers() {
|
|||
}
|
||||
|
||||
// ID_AA64ISAR1_EL1
|
||||
isar1 := getisar1()
|
||||
|
||||
switch extractBits(isar1, 0, 3) {
|
||||
case 1:
|
||||
ARM64.HasDCPOP = true
|
||||
|
@ -109,8 +145,6 @@ func readARM64Registers() {
|
|||
}
|
||||
|
||||
// ID_AA64PFR0_EL1
|
||||
pfr0 := getpfr0()
|
||||
|
||||
switch extractBits(pfr0, 16, 19) {
|
||||
case 0:
|
||||
ARM64.HasFP = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
// +build gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
//go:build gc
|
||||
// +build gc
|
||||
|
||||
package cpu
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
//go:build gc
|
||||
// +build gc
|
||||
|
||||
package cpu
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (386 || amd64 || amd64p32) && gc
|
||||
// +build 386 amd64 amd64p32
|
||||
// +build !gccgo
|
||||
// +build gc
|
||||
|
||||
package cpu
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gccgo
|
||||
// +build gccgo
|
||||
|
||||
package cpu
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gccgo
|
||||
// +build gccgo
|
||||
|
||||
package cpu
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (386 || amd64 || amd64p32) && gccgo
|
||||
// +build 386 amd64 amd64p32
|
||||
// +build gccgo
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !386 && !amd64 && !amd64p32 && !arm64
|
||||
// +build !386,!amd64,!amd64p32,!arm64
|
||||
|
||||
package cpu
|
||||
|
||||
func init() {
|
||||
func archInit() {
|
||||
if err := readHWCAP(); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux && (mips64 || mips64le)
|
||||
// +build linux
|
||||
// +build mips64 mips64le
|
||||
|
||||
package cpu
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x
|
||||
// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x
|
||||
|
||||
package cpu
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux && (ppc64 || ppc64le)
|
||||
// +build linux
|
||||
// +build ppc64 ppc64le
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 128
|
||||
|
||||
// HWCAP/HWCAP2 bits. These are exposed by the kernel.
|
||||
const (
|
||||
// ISA Level
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 256
|
||||
|
||||
const (
|
||||
// bit mask values from /usr/include/bits/hwcap.h
|
||||
hwcap_ZARCH = 2
|
||||
|
@ -19,86 +17,7 @@ const (
|
|||
hwcap_VXE = 8192
|
||||
)
|
||||
|
||||
// bitIsSet reports whether the bit at index is set. The bit index
|
||||
// is in big endian order, so bit index 0 is the leftmost bit.
|
||||
func bitIsSet(bits []uint64, index uint) bool {
|
||||
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
||||
}
|
||||
|
||||
// function is the code for the named cryptographic function.
|
||||
type function uint8
|
||||
|
||||
const (
|
||||
// KM{,A,C,CTR} function codes
|
||||
aes128 function = 18 // AES-128
|
||||
aes192 function = 19 // AES-192
|
||||
aes256 function = 20 // AES-256
|
||||
|
||||
// K{I,L}MD function codes
|
||||
sha1 function = 1 // SHA-1
|
||||
sha256 function = 2 // SHA-256
|
||||
sha512 function = 3 // SHA-512
|
||||
sha3_224 function = 32 // SHA3-224
|
||||
sha3_256 function = 33 // SHA3-256
|
||||
sha3_384 function = 34 // SHA3-384
|
||||
sha3_512 function = 35 // SHA3-512
|
||||
shake128 function = 36 // SHAKE-128
|
||||
shake256 function = 37 // SHAKE-256
|
||||
|
||||
// KLMD function codes
|
||||
ghash function = 65 // GHASH
|
||||
)
|
||||
|
||||
// queryResult contains the result of a Query function
|
||||
// call. Bits are numbered in big endian order so the
|
||||
// leftmost bit (the MSB) is at index 0.
|
||||
type queryResult struct {
|
||||
bits [2]uint64
|
||||
}
|
||||
|
||||
// Has reports whether the given functions are present.
|
||||
func (q *queryResult) Has(fns ...function) bool {
|
||||
if len(fns) == 0 {
|
||||
panic("no function codes provided")
|
||||
}
|
||||
for _, f := range fns {
|
||||
if !bitIsSet(q.bits[:], uint(f)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// facility is a bit index for the named facility.
|
||||
type facility uint8
|
||||
|
||||
const (
|
||||
// cryptography facilities
|
||||
msa4 facility = 77 // message-security-assist extension 4
|
||||
msa8 facility = 146 // message-security-assist extension 8
|
||||
)
|
||||
|
||||
// facilityList contains the result of an STFLE call.
|
||||
// Bits are numbered in big endian order so the
|
||||
// leftmost bit (the MSB) is at index 0.
|
||||
type facilityList struct {
|
||||
bits [4]uint64
|
||||
}
|
||||
|
||||
// Has reports whether the given facilities are present.
|
||||
func (s *facilityList) Has(fs ...facility) bool {
|
||||
if len(fs) == 0 {
|
||||
panic("no facility bits provided")
|
||||
}
|
||||
for _, f := range fs {
|
||||
if !bitIsSet(s.bits[:], uint(f)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func doinit() {
|
||||
func initS390Xbase() {
|
||||
// test HWCAP bit vector
|
||||
has := func(featureMask uint) bool {
|
||||
return hwCap&featureMask == featureMask
|
||||
|
@ -118,44 +37,4 @@ func doinit() {
|
|||
if S390X.HasVX {
|
||||
S390X.HasVXE = has(hwcap_VXE)
|
||||
}
|
||||
|
||||
// We need implementations of stfle, km and so on
|
||||
// to detect cryptographic features.
|
||||
if !haveAsmFunctions() {
|
||||
return
|
||||
}
|
||||
|
||||
// optional cryptographic functions
|
||||
if S390X.HasMSA {
|
||||
aes := []function{aes128, aes192, aes256}
|
||||
|
||||
// cipher message
|
||||
km, kmc := kmQuery(), kmcQuery()
|
||||
S390X.HasAES = km.Has(aes...)
|
||||
S390X.HasAESCBC = kmc.Has(aes...)
|
||||
if S390X.HasSTFLE {
|
||||
facilities := stfle()
|
||||
if facilities.Has(msa4) {
|
||||
kmctr := kmctrQuery()
|
||||
S390X.HasAESCTR = kmctr.Has(aes...)
|
||||
}
|
||||
if facilities.Has(msa8) {
|
||||
kma := kmaQuery()
|
||||
S390X.HasAESGCM = kma.Has(aes...)
|
||||
}
|
||||
}
|
||||
|
||||
// compute message digest
|
||||
kimd := kimdQuery() // intermediate (no padding)
|
||||
klmd := klmdQuery() // last (padding)
|
||||
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
|
||||
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
|
||||
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
|
||||
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
|
||||
sha3 := []function{
|
||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||
shake128, shake256,
|
||||
}
|
||||
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build mips64 || mips64le
|
||||
// +build mips64 mips64le
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 32
|
||||
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "msa", Feature: &MIPS64X.HasMSA},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build mips || mipsle
|
||||
// +build mips mipsle
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 32
|
||||
|
||||
func initOptions() {}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Minimal copy of functionality from x/sys/unix so the cpu package can call
|
||||
// sysctl without depending on x/sys/unix.
|
||||
|
||||
const (
|
||||
_CTL_QUERY = -2
|
||||
|
||||
_SYSCTL_VERS_1 = 0x1000000
|
||||
)
|
||||
|
||||
var _zero uintptr
|
||||
|
||||
func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(mib) > 0 {
|
||||
_p0 = unsafe.Pointer(&mib[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
_, _, errno := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(_p0),
|
||||
uintptr(len(mib)),
|
||||
uintptr(unsafe.Pointer(old)),
|
||||
uintptr(unsafe.Pointer(oldlen)),
|
||||
uintptr(unsafe.Pointer(new)),
|
||||
uintptr(newlen))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sysctlNode struct {
|
||||
Flags uint32
|
||||
Num int32
|
||||
Name [32]int8
|
||||
Ver uint32
|
||||
__rsvd uint32
|
||||
Un [16]byte
|
||||
_sysctl_size [8]byte
|
||||
_sysctl_func [8]byte
|
||||
_sysctl_parent [8]byte
|
||||
_sysctl_desc [8]byte
|
||||
}
|
||||
|
||||
func sysctlNodes(mib []int32) ([]sysctlNode, error) {
|
||||
var olen uintptr
|
||||
|
||||
// Get a list of all sysctl nodes below the given MIB by performing
|
||||
// a sysctl for the given MIB with CTL_QUERY appended.
|
||||
mib = append(mib, _CTL_QUERY)
|
||||
qnode := sysctlNode{Flags: _SYSCTL_VERS_1}
|
||||
qp := (*byte)(unsafe.Pointer(&qnode))
|
||||
sz := unsafe.Sizeof(qnode)
|
||||
if err := sysctl(mib, nil, &olen, qp, sz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Now that we know the size, get the actual nodes.
|
||||
nodes := make([]sysctlNode, olen/sz)
|
||||
np := (*byte)(unsafe.Pointer(&nodes[0]))
|
||||
if err := sysctl(mib, np, &olen, qp, sz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func nametomib(name string) ([]int32, error) {
|
||||
// Split name into components.
|
||||
var parts []string
|
||||
last := 0
|
||||
for i := 0; i < len(name); i++ {
|
||||
if name[i] == '.' {
|
||||
parts = append(parts, name[last:i])
|
||||
last = i + 1
|
||||
}
|
||||
}
|
||||
parts = append(parts, name[last:])
|
||||
|
||||
mib := []int32{}
|
||||
// Discover the nodes and construct the MIB OID.
|
||||
for partno, part := range parts {
|
||||
nodes, err := sysctlNodes(mib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
n := make([]byte, 0)
|
||||
for i := range node.Name {
|
||||
if node.Name[i] != 0 {
|
||||
n = append(n, byte(node.Name[i]))
|
||||
}
|
||||
}
|
||||
if string(n) == part {
|
||||
mib = append(mib, int32(node.Num))
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(mib) != partno+1 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return mib, nil
|
||||
}
|
||||
|
||||
// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's <aarch64/armreg.h>
|
||||
type aarch64SysctlCPUID struct {
|
||||
midr uint64 /* Main ID Register */
|
||||
revidr uint64 /* Revision ID Register */
|
||||
mpidr uint64 /* Multiprocessor Affinity Register */
|
||||
aa64dfr0 uint64 /* A64 Debug Feature Register 0 */
|
||||
aa64dfr1 uint64 /* A64 Debug Feature Register 1 */
|
||||
aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */
|
||||
aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */
|
||||
aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */
|
||||
aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */
|
||||
aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */
|
||||
aa64pfr0 uint64 /* A64 Processor Feature Register 0 */
|
||||
aa64pfr1 uint64 /* A64 Processor Feature Register 1 */
|
||||
aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */
|
||||
mvfr0 uint32 /* Media and VFP Feature Register 0 */
|
||||
mvfr1 uint32 /* Media and VFP Feature Register 1 */
|
||||
mvfr2 uint32 /* Media and VFP Feature Register 2 */
|
||||
pad uint32
|
||||
clidr uint64 /* Cache Level ID Register */
|
||||
ctr uint64 /* Cache Type Register */
|
||||
}
|
||||
|
||||
func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) {
|
||||
mib, err := nametomib(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := aarch64SysctlCPUID{}
|
||||
n := unsafe.Sizeof(out)
|
||||
_, _, errno := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(len(mib)),
|
||||
uintptr(unsafe.Pointer(&out)),
|
||||
uintptr(unsafe.Pointer(&n)),
|
||||
uintptr(0),
|
||||
uintptr(0))
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func doinit() {
|
||||
cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id")
|
||||
if err != nil {
|
||||
setMinimalFeatures()
|
||||
return
|
||||
}
|
||||
parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0)
|
||||
|
||||
Initialized = true
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux && arm
|
||||
// +build !linux,arm
|
||||
|
||||
package cpu
|
||||
|
||||
func archInit() {}
|
|
@ -2,7 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !linux,arm64
|
||||
//go:build !linux && !netbsd && arm64
|
||||
// +build !linux,!netbsd,arm64
|
||||
|
||||
package cpu
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux && (mips64 || mips64le)
|
||||
// +build !linux
|
||||
// +build mips64 mips64le
|
||||
|
||||
package cpu
|
||||
|
||||
func archInit() {
|
||||
Initialized = true
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ppc64 || ppc64le
|
||||
// +build ppc64 ppc64le
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 128
|
||||
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "darn", Feature: &PPC64.HasDARN},
|
||||
{Name: "scv", Feature: &PPC64.HasSCV},
|
||||
}
|
||||
}
|
|
@ -2,8 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build riscv64
|
||||
// +build riscv64
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 32
|
||||
|
||||
func initOptions() {}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
const cacheLineSize = 256
|
||||
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "zarch", Feature: &S390X.HasZARCH, Required: true},
|
||||
{Name: "stfle", Feature: &S390X.HasSTFLE, Required: true},
|
||||
{Name: "ldisp", Feature: &S390X.HasLDISP, Required: true},
|
||||
{Name: "eimm", Feature: &S390X.HasEIMM, Required: true},
|
||||
{Name: "dfp", Feature: &S390X.HasDFP},
|
||||
{Name: "etf3eh", Feature: &S390X.HasETF3EH},
|
||||
{Name: "msa", Feature: &S390X.HasMSA},
|
||||
{Name: "aes", Feature: &S390X.HasAES},
|
||||
{Name: "aescbc", Feature: &S390X.HasAESCBC},
|
||||
{Name: "aesctr", Feature: &S390X.HasAESCTR},
|
||||
{Name: "aesgcm", Feature: &S390X.HasAESGCM},
|
||||
{Name: "ghash", Feature: &S390X.HasGHASH},
|
||||
{Name: "sha1", Feature: &S390X.HasSHA1},
|
||||
{Name: "sha256", Feature: &S390X.HasSHA256},
|
||||
{Name: "sha3", Feature: &S390X.HasSHA3},
|
||||
{Name: "sha512", Feature: &S390X.HasSHA512},
|
||||
{Name: "vx", Feature: &S390X.HasVX},
|
||||
{Name: "vxe", Feature: &S390X.HasVXE},
|
||||
}
|
||||
}
|
||||
|
||||
// bitIsSet reports whether the bit at index is set. The bit index
|
||||
// is in big endian order, so bit index 0 is the leftmost bit.
|
||||
func bitIsSet(bits []uint64, index uint) bool {
|
||||
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
||||
}
|
||||
|
||||
// facility is a bit index for the named facility.
|
||||
type facility uint8
|
||||
|
||||
const (
|
||||
// mandatory facilities
|
||||
zarch facility = 1 // z architecture mode is active
|
||||
stflef facility = 7 // store-facility-list-extended
|
||||
ldisp facility = 18 // long-displacement
|
||||
eimm facility = 21 // extended-immediate
|
||||
|
||||
// miscellaneous facilities
|
||||
dfp facility = 42 // decimal-floating-point
|
||||
etf3eh facility = 30 // extended-translation 3 enhancement
|
||||
|
||||
// cryptography facilities
|
||||
msa facility = 17 // message-security-assist
|
||||
msa3 facility = 76 // message-security-assist extension 3
|
||||
msa4 facility = 77 // message-security-assist extension 4
|
||||
msa5 facility = 57 // message-security-assist extension 5
|
||||
msa8 facility = 146 // message-security-assist extension 8
|
||||
msa9 facility = 155 // message-security-assist extension 9
|
||||
|
||||
// vector facilities
|
||||
vx facility = 129 // vector facility
|
||||
vxe facility = 135 // vector-enhancements 1
|
||||
vxe2 facility = 148 // vector-enhancements 2
|
||||
)
|
||||
|
||||
// facilityList contains the result of an STFLE call.
|
||||
// Bits are numbered in big endian order so the
|
||||
// leftmost bit (the MSB) is at index 0.
|
||||
type facilityList struct {
|
||||
bits [4]uint64
|
||||
}
|
||||
|
||||
// Has reports whether the given facilities are present.
|
||||
func (s *facilityList) Has(fs ...facility) bool {
|
||||
if len(fs) == 0 {
|
||||
panic("no facility bits provided")
|
||||
}
|
||||
for _, f := range fs {
|
||||
if !bitIsSet(s.bits[:], uint(f)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// function is the code for the named cryptographic function.
|
||||
type function uint8
|
||||
|
||||
const (
|
||||
// KM{,A,C,CTR} function codes
|
||||
aes128 function = 18 // AES-128
|
||||
aes192 function = 19 // AES-192
|
||||
aes256 function = 20 // AES-256
|
||||
|
||||
// K{I,L}MD function codes
|
||||
sha1 function = 1 // SHA-1
|
||||
sha256 function = 2 // SHA-256
|
||||
sha512 function = 3 // SHA-512
|
||||
sha3_224 function = 32 // SHA3-224
|
||||
sha3_256 function = 33 // SHA3-256
|
||||
sha3_384 function = 34 // SHA3-384
|
||||
sha3_512 function = 35 // SHA3-512
|
||||
shake128 function = 36 // SHAKE-128
|
||||
shake256 function = 37 // SHAKE-256
|
||||
|
||||
// KLMD function codes
|
||||
ghash function = 65 // GHASH
|
||||
)
|
||||
|
||||
// queryResult contains the result of a Query function
|
||||
// call. Bits are numbered in big endian order so the
|
||||
// leftmost bit (the MSB) is at index 0.
|
||||
type queryResult struct {
|
||||
bits [2]uint64
|
||||
}
|
||||
|
||||
// Has reports whether the given functions are present.
|
||||
func (q *queryResult) Has(fns ...function) bool {
|
||||
if len(fns) == 0 {
|
||||
panic("no function codes provided")
|
||||
}
|
||||
for _, f := range fns {
|
||||
if !bitIsSet(q.bits[:], uint(f)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func doinit() {
|
||||
initS390Xbase()
|
||||
|
||||
// We need implementations of stfle, km and so on
|
||||
// to detect cryptographic features.
|
||||
if !haveAsmFunctions() {
|
||||
return
|
||||
}
|
||||
|
||||
// optional cryptographic functions
|
||||
if S390X.HasMSA {
|
||||
aes := []function{aes128, aes192, aes256}
|
||||
|
||||
// cipher message
|
||||
km, kmc := kmQuery(), kmcQuery()
|
||||
S390X.HasAES = km.Has(aes...)
|
||||
S390X.HasAESCBC = kmc.Has(aes...)
|
||||
if S390X.HasSTFLE {
|
||||
facilities := stfle()
|
||||
if facilities.Has(msa4) {
|
||||
kmctr := kmctrQuery()
|
||||
S390X.HasAESCTR = kmctr.Has(aes...)
|
||||
}
|
||||
if facilities.Has(msa8) {
|
||||
kma := kmaQuery()
|
||||
S390X.HasAESGCM = kma.Has(aes...)
|
||||
}
|
||||
}
|
||||
|
||||
// compute message digest
|
||||
kimd := kimdQuery() // intermediate (no padding)
|
||||
klmd := klmdQuery() // last (padding)
|
||||
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
|
||||
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
|
||||
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
|
||||
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
|
||||
sha3 := []function{
|
||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||
shake128, shake256,
|
||||
}
|
||||
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
// +build gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build wasm
|
||||
// +build wasm
|
||||
|
||||
package cpu
|
||||
|
@ -11,3 +12,7 @@ package cpu
|
|||
// rules are good enough.
|
||||
|
||||
const cacheLineSize = 0
|
||||
|
||||
func initOptions() {}
|
||||
|
||||
func archInit() {}
|
||||
|
|
|
@ -2,13 +2,62 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build 386 || amd64 || amd64p32
|
||||
// +build 386 amd64 amd64p32
|
||||
|
||||
package cpu
|
||||
|
||||
import "runtime"
|
||||
|
||||
const cacheLineSize = 64
|
||||
|
||||
func init() {
|
||||
func initOptions() {
|
||||
options = []option{
|
||||
{Name: "adx", Feature: &X86.HasADX},
|
||||
{Name: "aes", Feature: &X86.HasAES},
|
||||
{Name: "avx", Feature: &X86.HasAVX},
|
||||
{Name: "avx2", Feature: &X86.HasAVX2},
|
||||
{Name: "avx512", Feature: &X86.HasAVX512},
|
||||
{Name: "avx512f", Feature: &X86.HasAVX512F},
|
||||
{Name: "avx512cd", Feature: &X86.HasAVX512CD},
|
||||
{Name: "avx512er", Feature: &X86.HasAVX512ER},
|
||||
{Name: "avx512pf", Feature: &X86.HasAVX512PF},
|
||||
{Name: "avx512vl", Feature: &X86.HasAVX512VL},
|
||||
{Name: "avx512bw", Feature: &X86.HasAVX512BW},
|
||||
{Name: "avx512dq", Feature: &X86.HasAVX512DQ},
|
||||
{Name: "avx512ifma", Feature: &X86.HasAVX512IFMA},
|
||||
{Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI},
|
||||
{Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW},
|
||||
{Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS},
|
||||
{Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ},
|
||||
{Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ},
|
||||
{Name: "avx512vnni", Feature: &X86.HasAVX512VNNI},
|
||||
{Name: "avx512gfni", Feature: &X86.HasAVX512GFNI},
|
||||
{Name: "avx512vaes", Feature: &X86.HasAVX512VAES},
|
||||
{Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2},
|
||||
{Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG},
|
||||
{Name: "avx512bf16", Feature: &X86.HasAVX512BF16},
|
||||
{Name: "bmi1", Feature: &X86.HasBMI1},
|
||||
{Name: "bmi2", Feature: &X86.HasBMI2},
|
||||
{Name: "erms", Feature: &X86.HasERMS},
|
||||
{Name: "fma", Feature: &X86.HasFMA},
|
||||
{Name: "osxsave", Feature: &X86.HasOSXSAVE},
|
||||
{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
|
||||
{Name: "popcnt", Feature: &X86.HasPOPCNT},
|
||||
{Name: "rdrand", Feature: &X86.HasRDRAND},
|
||||
{Name: "rdseed", Feature: &X86.HasRDSEED},
|
||||
{Name: "sse3", Feature: &X86.HasSSE3},
|
||||
{Name: "sse41", Feature: &X86.HasSSE41},
|
||||
{Name: "sse42", Feature: &X86.HasSSE42},
|
||||
{Name: "ssse3", Feature: &X86.HasSSSE3},
|
||||
|
||||
// These capabilities should always be enabled on amd64:
|
||||
{Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"},
|
||||
}
|
||||
}
|
||||
|
||||
func archInit() {
|
||||
|
||||
Initialized = true
|
||||
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
|
@ -31,12 +80,15 @@ func init() {
|
|||
X86.HasOSXSAVE = isSet(27, ecx1)
|
||||
X86.HasRDRAND = isSet(30, ecx1)
|
||||
|
||||
osSupportsAVX := false
|
||||
var osSupportsAVX, osSupportsAVX512 bool
|
||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||
if X86.HasOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
// Check if XMM and YMM registers have OS support.
|
||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||
|
||||
// Check if OPMASK and ZMM registers have OS support.
|
||||
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax)
|
||||
}
|
||||
|
||||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
||||
|
@ -45,13 +97,38 @@ func init() {
|
|||
return
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
_, ebx7, ecx7, edx7 := cpuid(7, 0)
|
||||
X86.HasBMI1 = isSet(3, ebx7)
|
||||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
|
||||
X86.HasBMI2 = isSet(8, ebx7)
|
||||
X86.HasERMS = isSet(9, ebx7)
|
||||
X86.HasRDSEED = isSet(18, ebx7)
|
||||
X86.HasADX = isSet(19, ebx7)
|
||||
|
||||
X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||
if X86.HasAVX512 {
|
||||
X86.HasAVX512F = true
|
||||
X86.HasAVX512CD = isSet(28, ebx7)
|
||||
X86.HasAVX512ER = isSet(27, ebx7)
|
||||
X86.HasAVX512PF = isSet(26, ebx7)
|
||||
X86.HasAVX512VL = isSet(31, ebx7)
|
||||
X86.HasAVX512BW = isSet(30, ebx7)
|
||||
X86.HasAVX512DQ = isSet(17, ebx7)
|
||||
X86.HasAVX512IFMA = isSet(21, ebx7)
|
||||
X86.HasAVX512VBMI = isSet(1, ecx7)
|
||||
X86.HasAVX5124VNNIW = isSet(2, edx7)
|
||||
X86.HasAVX5124FMAPS = isSet(3, edx7)
|
||||
X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7)
|
||||
X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7)
|
||||
X86.HasAVX512VNNI = isSet(11, ecx7)
|
||||
X86.HasAVX512GFNI = isSet(8, ecx7)
|
||||
X86.HasAVX512VAES = isSet(9, ecx7)
|
||||
X86.HasAVX512VBMI2 = isSet(6, ecx7)
|
||||
X86.HasAVX512BITALG = isSet(12, ecx7)
|
||||
|
||||
eax71, _, _, _ := cpuid(7, 1)
|
||||
X86.HasAVX512BF16 = isSet(5, eax71)
|
||||
}
|
||||
}
|
||||
|
||||
func isSet(bitpos uint, value uint32) bool {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build 386 amd64 amd64p32
|
||||
// +build !gccgo
|
||||
// +build gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
func archInit() {
|
||||
doinit()
|
||||
Initialized = true
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
func initS390Xbase() {
|
||||
// get the facilities list
|
||||
facilities := stfle()
|
||||
|
||||
// mandatory
|
||||
S390X.HasZARCH = facilities.Has(zarch)
|
||||
S390X.HasSTFLE = facilities.Has(stflef)
|
||||
S390X.HasLDISP = facilities.Has(ldisp)
|
||||
S390X.HasEIMM = facilities.Has(eimm)
|
||||
|
||||
// optional
|
||||
S390X.HasETF3EH = facilities.Has(etf3eh)
|
||||
S390X.HasDFP = facilities.Has(dfp)
|
||||
S390X.HasMSA = facilities.Has(msa)
|
||||
S390X.HasVX = facilities.Has(vx)
|
||||
if S390X.HasVX {
|
||||
S390X.HasVXE = facilities.Has(vxe)
|
||||
}
|
||||
}
|