mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-30 17:00:57 -06:00
build(deps): bump github.com/gookit/config/v2 from 2.2.6 to 2.2.7
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.6 to 2.2.7. - [Release notes](https://github.com/gookit/config/releases) - [Commits](https://github.com/gookit/config/compare/v2.2.6...v2.2.7) --- updated-dependencies: - dependency-name: github.com/gookit/config/v2 dependency-version: 2.2.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
7
go.mod
7
go.mod
@@ -40,7 +40,7 @@ require (
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/go-tika v0.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gookit/config/v2 v2.2.6
|
||||
github.com/gookit/config/v2 v2.2.7
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1
|
||||
github.com/invopop/validation v0.8.0
|
||||
@@ -203,6 +203,7 @@ require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/go-test/deep v1.1.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
@@ -219,8 +220,7 @@ require (
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
github.com/gookit/goutil v0.6.18 // indirect
|
||||
github.com/gookit/goutil v0.7.1 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
@@ -314,7 +314,6 @@ require (
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
|
||||
|
||||
18
go.sum
18
go.sum
@@ -430,6 +430,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
||||
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
@@ -551,14 +553,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
||||
github.com/gookit/config/v2 v2.2.6 h1:8ZbkSr3gnFg1En8za9X3vldnZca3y3C7kaBLGsdLghE=
|
||||
github.com/gookit/config/v2 v2.2.6/go.mod h1:++APDf3Ebj6mjzW1ALkegvg1evQKyx4FpuQqQZ2s2WM=
|
||||
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
|
||||
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
|
||||
github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E=
|
||||
github.com/gookit/ini/v2 v2.2.3/go.mod h1:Vu6p7P7xcfmb8KYu3L0ek8bqu/Im63N81q208SCCZY4=
|
||||
github.com/gookit/config/v2 v2.2.7 h1:P58/uENzkDp7r7Hp8YSZxOhZ/F5a5Y/AzyhDUkQYa9A=
|
||||
github.com/gookit/config/v2 v2.2.7/go.mod h1:QST99HmkZXXD/HkZmOm1OXpgdAnc6Rl9syGl+u62Pi8=
|
||||
github.com/gookit/goutil v0.7.1 h1:AaFJPN9mrdeYBv8HOybri26EHGCC34WJVT7jUStGJsI=
|
||||
github.com/gookit/goutil v0.7.1/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU=
|
||||
github.com/gookit/ini/v2 v2.3.2 h1:W6tzOGE6zOLQelH2xhcH8BIBZPtnEpJgQ+J6SsAKBSw=
|
||||
github.com/gookit/ini/v2 v2.3.2/go.mod h1:StKSqY5niArRwYBS8Z71+iWUt5ow47qt359sS9YQLYY=
|
||||
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
|
||||
@@ -1141,8 +1141,6 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA=
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
|
||||
|
||||
21
vendor/github.com/go-viper/mapstructure/v2/.editorconfig
generated
vendored
Normal file
21
vendor/github.com/go-viper/mapstructure/v2/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
||||
[{Makefile,*.mk}]
|
||||
indent_style = tab
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
|
||||
[.golangci.yaml]
|
||||
indent_size = 2
|
||||
6
vendor/github.com/go-viper/mapstructure/v2/.gitignore
generated
vendored
Normal file
6
vendor/github.com/go-viper/mapstructure/v2/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/.devenv/
|
||||
/.direnv/
|
||||
/.pre-commit-config.yaml
|
||||
/bin/
|
||||
/build/
|
||||
/var/
|
||||
48
vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml
generated
vendored
Normal file
48
vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- govet
|
||||
- ineffassign
|
||||
# - misspell
|
||||
- nolintlint
|
||||
# - revive
|
||||
|
||||
disable:
|
||||
- errcheck
|
||||
- staticcheck
|
||||
- unused
|
||||
|
||||
settings:
|
||||
misspell:
|
||||
locale: US
|
||||
nolintlint:
|
||||
allow-unused: false # report any unused nolint directives
|
||||
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
# - golines
|
||||
|
||||
settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- localmodule
|
||||
gofmt:
|
||||
simplify: true
|
||||
rewrite-rules:
|
||||
- pattern: interface{}
|
||||
replacement: any
|
||||
|
||||
exclusions:
|
||||
paths:
|
||||
- internal/
|
||||
104
vendor/github.com/go-viper/mapstructure/v2/CHANGELOG.md
generated
vendored
Normal file
104
vendor/github.com/go-viper/mapstructure/v2/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
> [!WARNING]
|
||||
> As of v2 of this library, change log can be found in GitHub releases.
|
||||
|
||||
## 1.5.1
|
||||
|
||||
* Wrap errors so they're compatible with `errors.Is` and `errors.As` [GH-282]
|
||||
* Fix map of slices not decoding properly in certain cases. [GH-266]
|
||||
|
||||
## 1.5.0
|
||||
|
||||
* New option `IgnoreUntaggedFields` to ignore decoding to any fields
|
||||
without `mapstructure` (or the configured tag name) set [GH-277]
|
||||
* New option `ErrorUnset` which makes it an error if any fields
|
||||
in a target struct are not set by the decoding process. [GH-225]
|
||||
* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240]
|
||||
* Decoding to slice from array no longer crashes [GH-265]
|
||||
* Decode nested struct pointers to map [GH-271]
|
||||
* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280]
|
||||
* Fix issue where fields with `,omitempty` would sometimes decode
|
||||
into a map with an empty string key [GH-281]
|
||||
|
||||
## 1.4.3
|
||||
|
||||
* Fix cases where `json.Number` didn't decode properly [GH-261]
|
||||
|
||||
## 1.4.2
|
||||
|
||||
* Custom name matchers to support any sort of casing, formatting, etc. for
|
||||
field names. [GH-250]
|
||||
* Fix possible panic in ComposeDecodeHookFunc [GH-251]
|
||||
|
||||
## 1.4.1
|
||||
|
||||
* Fix regression where `*time.Time` value would be set to empty and not be sent
|
||||
to decode hooks properly [GH-232]
|
||||
|
||||
## 1.4.0
|
||||
|
||||
* A new decode hook type `DecodeHookFuncValue` has been added that has
|
||||
access to the full values. [GH-183]
|
||||
* Squash is now supported with embedded fields that are struct pointers [GH-205]
|
||||
* Empty strings will convert to 0 for all numeric types when weakly decoding [GH-206]
|
||||
|
||||
## 1.3.3
|
||||
|
||||
* Decoding maps from maps creates a settable value for decode hooks [GH-203]
|
||||
|
||||
## 1.3.2
|
||||
|
||||
* Decode into interface type with a struct value is supported [GH-187]
|
||||
|
||||
## 1.3.1
|
||||
|
||||
* Squash should only squash embedded structs. [GH-194]
|
||||
|
||||
## 1.3.0
|
||||
|
||||
* Added `",omitempty"` support. This will ignore zero values in the source
|
||||
structure when encoding. [GH-145]
|
||||
|
||||
## 1.2.3
|
||||
|
||||
* Fix duplicate entries in Keys list with pointer values. [GH-185]
|
||||
|
||||
## 1.2.2
|
||||
|
||||
* Do not add unsettable (unexported) values to the unused metadata key
|
||||
or "remain" value. [GH-150]
|
||||
|
||||
## 1.2.1
|
||||
|
||||
* Go modules checksum mismatch fix
|
||||
|
||||
## 1.2.0
|
||||
|
||||
* Added support to capture unused values in a field using the `",remain"` value
|
||||
in the mapstructure tag. There is an example to showcase usage.
|
||||
* Added `DecoderConfig` option to always squash embedded structs
|
||||
* `json.Number` can decode into `uint` types
|
||||
* Empty slices are preserved and not replaced with nil slices
|
||||
* Fix panic that can occur in when decoding a map into a nil slice of structs
|
||||
* Improved package documentation for godoc
|
||||
|
||||
## 1.1.2
|
||||
|
||||
* Fix error when decode hook decodes interface implementation into interface
|
||||
type. [GH-140]
|
||||
|
||||
## 1.1.1
|
||||
|
||||
* Fix panic that can happen in `decodePtr`
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133]
|
||||
* Support struct to struct decoding [GH-137]
|
||||
* If source map value is nil, then destination map value is nil (instead of empty)
|
||||
* If source slice value is nil, then destination slice value is nil (instead of empty)
|
||||
* If source pointer is nil, then destination pointer is set to nil (instead of
|
||||
allocated zero value of type)
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Initial tagged stable release.
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Anmol Sethi
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -9,13 +9,13 @@ 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 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.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
81
vendor/github.com/go-viper/mapstructure/v2/README.md
generated
vendored
Normal file
81
vendor/github.com/go-viper/mapstructure/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
# mapstructure
|
||||
|
||||
[](https://github.com/go-viper/mapstructure/actions/workflows/ci.yaml)
|
||||
[](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2)
|
||||

|
||||
[](https://deps.dev/go/github.com%252Fgo-viper%252Fmapstructure%252Fv2)
|
||||
|
||||
mapstructure is a Go library for decoding generic map values to structures
|
||||
and vice versa, while providing helpful error handling.
|
||||
|
||||
This library is most useful when decoding values from some data stream (JSON,
|
||||
Gob, etc.) where you don't _quite_ know the structure of the underlying data
|
||||
until you read a part of it. You can therefore read a `map[string]interface{}`
|
||||
and use this library to decode it into the proper underlying native Go
|
||||
structure.
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
go get github.com/go-viper/mapstructure/v2
|
||||
```
|
||||
|
||||
## Migrating from `github.com/mitchellh/mapstructure`
|
||||
|
||||
[@mitchehllh](https://github.com/mitchellh) announced his intent to archive some of his unmaintained projects (see [here](https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc) and [here](https://github.com/mitchellh/mapstructure/issues/349)). This is a repository achieved the "blessed fork" status.
|
||||
|
||||
You can migrate to this package by changing your import paths in your Go files to `github.com/go-viper/mapstructure/v2`.
|
||||
The API is the same, so you don't need to change anything else.
|
||||
|
||||
Here is a script that can help you with the migration:
|
||||
|
||||
```shell
|
||||
sed -i 's|github.com/mitchellh/mapstructure|github.com/go-viper/mapstructure/v2|g' $(find . -type f -name '*.go')
|
||||
```
|
||||
|
||||
If you need more time to migrate your code, that is absolutely fine.
|
||||
|
||||
Some of the latest fixes are backported to the v1 release branch of this package, so you can use the Go modules `replace` feature until you are ready to migrate:
|
||||
|
||||
```shell
|
||||
replace github.com/mitchellh/mapstructure => github.com/go-viper/mapstructure v1.6.0
|
||||
```
|
||||
|
||||
## Usage & Example
|
||||
|
||||
For usage and examples see the [documentation](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2).
|
||||
|
||||
The `Decode` function has examples associated with it there.
|
||||
|
||||
## But Why?!
|
||||
|
||||
Go offers fantastic standard libraries for decoding formats such as JSON.
|
||||
The standard method is to have a struct pre-created, and populate that struct
|
||||
from the bytes of the encoded format. This is great, but the problem is if
|
||||
you have configuration or an encoding that changes slightly depending on
|
||||
specific fields. For example, consider this JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "person",
|
||||
"name": "Mitchell"
|
||||
}
|
||||
```
|
||||
|
||||
Perhaps we can't populate a specific structure without first reading
|
||||
the "type" field from the JSON. We could always do two passes over the
|
||||
decoding of the JSON (reading the "type" first, and the rest later).
|
||||
However, it is much simpler to just decode this into a `map[string]interface{}`
|
||||
structure, read the "type" key, then use something like this library
|
||||
to decode it into the proper structure.
|
||||
|
||||
## Credits
|
||||
|
||||
Mapstructure was originally created by [@mitchellh](https://github.com/mitchellh).
|
||||
This is a maintained fork of the original library.
|
||||
|
||||
Read more about the reasons for the fork [here](https://github.com/mitchellh/mapstructure/issues/349).
|
||||
|
||||
## License
|
||||
|
||||
The project is licensed under the [MIT License](LICENSE).
|
||||
714
vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go
generated
vendored
Normal file
714
vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go
generated
vendored
Normal file
@@ -0,0 +1,714 @@
|
||||
package mapstructure
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// typedDecodeHook takes a raw DecodeHookFunc (an any) and turns
|
||||
// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
|
||||
func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
|
||||
// Create variables here so we can reference them with the reflect pkg
|
||||
var f1 DecodeHookFuncType
|
||||
var f2 DecodeHookFuncKind
|
||||
var f3 DecodeHookFuncValue
|
||||
|
||||
// Fill in the variables into this interface and the rest is done
|
||||
// automatically using the reflect package.
|
||||
potential := []any{f1, f2, f3}
|
||||
|
||||
v := reflect.ValueOf(h)
|
||||
vt := v.Type()
|
||||
for _, raw := range potential {
|
||||
pt := reflect.ValueOf(raw).Type()
|
||||
if vt.ConvertibleTo(pt) {
|
||||
return v.Convert(pt).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns
|
||||
// it into a closure to be used directly
|
||||
// if the type fails to convert we return a closure always erroring to keep the previous behaviour
|
||||
func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (any, error) {
|
||||
switch f := typedDecodeHook(raw).(type) {
|
||||
case DecodeHookFuncType:
|
||||
return func(from reflect.Value, to reflect.Value) (any, error) {
|
||||
return f(from.Type(), to.Type(), from.Interface())
|
||||
}
|
||||
case DecodeHookFuncKind:
|
||||
return func(from reflect.Value, to reflect.Value) (any, error) {
|
||||
return f(from.Kind(), to.Kind(), from.Interface())
|
||||
}
|
||||
case DecodeHookFuncValue:
|
||||
return func(from reflect.Value, to reflect.Value) (any, error) {
|
||||
return f(from, to)
|
||||
}
|
||||
default:
|
||||
return func(from reflect.Value, to reflect.Value) (any, error) {
|
||||
return nil, errors.New("invalid decode hook signature")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeHookExec executes the given decode hook. This should be used
|
||||
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
||||
// that took reflect.Kind instead of reflect.Type.
|
||||
func DecodeHookExec(
|
||||
raw DecodeHookFunc,
|
||||
from reflect.Value, to reflect.Value,
|
||||
) (any, error) {
|
||||
switch f := typedDecodeHook(raw).(type) {
|
||||
case DecodeHookFuncType:
|
||||
return f(from.Type(), to.Type(), from.Interface())
|
||||
case DecodeHookFuncKind:
|
||||
return f(from.Kind(), to.Kind(), from.Interface())
|
||||
case DecodeHookFuncValue:
|
||||
return f(from, to)
|
||||
default:
|
||||
return nil, errors.New("invalid decode hook signature")
|
||||
}
|
||||
}
|
||||
|
||||
// ComposeDecodeHookFunc creates a single DecodeHookFunc that
|
||||
// automatically composes multiple DecodeHookFuncs.
|
||||
//
|
||||
// The composed funcs are called in order, with the result of the
|
||||
// previous transformation.
|
||||
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||
cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(fs))
|
||||
for _, f := range fs {
|
||||
cached = append(cached, cachedDecodeHook(f))
|
||||
}
|
||||
return func(f reflect.Value, t reflect.Value) (any, error) {
|
||||
var err error
|
||||
data := f.Interface()
|
||||
|
||||
newFrom := f
|
||||
for _, c := range cached {
|
||||
data, err = c(newFrom, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := data.(reflect.Value); ok {
|
||||
newFrom = v
|
||||
} else {
|
||||
newFrom = reflect.ValueOf(data)
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
|
||||
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
|
||||
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
|
||||
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
|
||||
cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(ff))
|
||||
for _, f := range ff {
|
||||
cached = append(cached, cachedDecodeHook(f))
|
||||
}
|
||||
return func(a, b reflect.Value) (any, error) {
|
||||
var allErrs string
|
||||
var out any
|
||||
var err error
|
||||
|
||||
for _, c := range cached {
|
||||
out, err = c(a, b)
|
||||
if err != nil {
|
||||
allErrs += err.Error() + "\n"
|
||||
continue
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
return nil, errors.New(allErrs)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToSliceHookFunc returns a DecodeHookFunc that converts
|
||||
// string to []string by splitting on the given sep.
|
||||
func StringToSliceHookFunc(sep string) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.SliceOf(f) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
raw := data.(string)
|
||||
if raw == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
return strings.Split(raw, sep), nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc].
|
||||
//
|
||||
// As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice.
|
||||
// This function removes that check.
|
||||
func StringToWeakSliceHookFunc(sep string) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Slice {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
raw := data.(string)
|
||||
if raw == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
return strings.Split(raw, sep), nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to time.Duration.
|
||||
func StringToTimeDurationHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(time.Duration(5)) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
d, err := time.ParseDuration(data.(string))
|
||||
|
||||
return d, wrapTimeParseDurationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToTimeLocationHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to *time.Location.
|
||||
func StringToTimeLocationHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(time.Local) {
|
||||
return data, nil
|
||||
}
|
||||
d, err := time.LoadLocation(data.(string))
|
||||
|
||||
return d, wrapTimeParseLocationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToURLHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to *url.URL.
|
||||
func StringToURLHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(&url.URL{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u, err := url.Parse(data.(string))
|
||||
|
||||
return u, wrapUrlError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToIPHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to net.IP
|
||||
func StringToIPHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(net.IP{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
ip := net.ParseIP(data.(string))
|
||||
if ip == nil {
|
||||
return net.IP{}, fmt.Errorf("failed parsing ip")
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToIPNetHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to net.IPNet
|
||||
func StringToIPNetHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(net.IPNet{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
_, net, err := net.ParseCIDR(data.(string))
|
||||
return net, wrapNetParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToTimeHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to time.Time.
|
||||
func StringToTimeHookFunc(layout string) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(time.Time{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
ti, err := time.Parse(layout, data.(string))
|
||||
|
||||
return ti, wrapTimeParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
|
||||
// the decoder.
|
||||
//
|
||||
// Note that this is significantly different from the WeaklyTypedInput option
|
||||
// of the DecoderConfig.
|
||||
func WeaklyTypedHook(
|
||||
f reflect.Kind,
|
||||
t reflect.Kind,
|
||||
data any,
|
||||
) (any, error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
switch t {
|
||||
case reflect.String:
|
||||
switch f {
|
||||
case reflect.Bool:
|
||||
if dataVal.Bool() {
|
||||
return "1", nil
|
||||
}
|
||||
return "0", nil
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
|
||||
case reflect.Int:
|
||||
return strconv.FormatInt(dataVal.Int(), 10), nil
|
||||
case reflect.Slice:
|
||||
dataType := dataVal.Type()
|
||||
elemKind := dataType.Elem().Kind()
|
||||
if elemKind == reflect.Uint8 {
|
||||
return string(dataVal.Interface().([]uint8)), nil
|
||||
}
|
||||
case reflect.Uint:
|
||||
return strconv.FormatUint(dataVal.Uint(), 10), nil
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func RecursiveStructToMapHookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Value, t reflect.Value) (any, error) {
|
||||
if f.Kind() != reflect.Struct {
|
||||
return f.Interface(), nil
|
||||
}
|
||||
|
||||
var i any = struct{}{}
|
||||
if t.Type() != reflect.TypeOf(&i).Elem() {
|
||||
return f.Interface(), nil
|
||||
}
|
||||
|
||||
m := make(map[string]any)
|
||||
t.Set(reflect.ValueOf(m))
|
||||
|
||||
return f.Interface(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies
|
||||
// strings to the UnmarshalText function, when the target type
|
||||
// implements the encoding.TextUnmarshaler interface
|
||||
func TextUnmarshallerHookFunc() DecodeHookFuncType {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
result := reflect.New(t).Interface()
|
||||
unmarshaller, ok := result.(encoding.TextUnmarshaler)
|
||||
if !ok {
|
||||
return data, nil
|
||||
}
|
||||
str, ok := data.(string)
|
||||
if !ok {
|
||||
str = reflect.Indirect(reflect.ValueOf(&data)).Elem().String()
|
||||
}
|
||||
if err := unmarshaller.UnmarshalText([]byte(str)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToNetIPAddrHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to netip.Addr.
|
||||
func StringToNetIPAddrHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(netip.Addr{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
addr, err := netip.ParseAddr(data.(string))
|
||||
|
||||
return addr, wrapNetIPParseAddrError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToNetIPAddrPortHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to netip.AddrPort.
|
||||
func StringToNetIPAddrPortHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(netip.AddrPort{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
addrPort, err := netip.ParseAddrPort(data.(string))
|
||||
|
||||
return addrPort, wrapNetIPParseAddrPortError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToNetIPPrefixHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to netip.Prefix.
|
||||
func StringToNetIPPrefixHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data any,
|
||||
) (any, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(netip.Prefix{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
prefix, err := netip.ParsePrefix(data.(string))
|
||||
|
||||
return prefix, wrapNetIPParsePrefixError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToBasicTypeHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to basic types.
|
||||
// int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, byte, rune, complex64, complex128
|
||||
func StringToBasicTypeHookFunc() DecodeHookFunc {
|
||||
return ComposeDecodeHookFunc(
|
||||
StringToInt8HookFunc(),
|
||||
StringToUint8HookFunc(),
|
||||
StringToInt16HookFunc(),
|
||||
StringToUint16HookFunc(),
|
||||
StringToInt32HookFunc(),
|
||||
StringToUint32HookFunc(),
|
||||
StringToInt64HookFunc(),
|
||||
StringToUint64HookFunc(),
|
||||
StringToIntHookFunc(),
|
||||
StringToUintHookFunc(),
|
||||
StringToFloat32HookFunc(),
|
||||
StringToFloat64HookFunc(),
|
||||
StringToBoolHookFunc(),
|
||||
// byte and rune are aliases for uint8 and int32 respectively
|
||||
// StringToByteHookFunc(),
|
||||
// StringToRuneHookFunc(),
|
||||
StringToComplex64HookFunc(),
|
||||
StringToComplex128HookFunc(),
|
||||
)
|
||||
}
|
||||
|
||||
// StringToInt8HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to int8.
|
||||
func StringToInt8HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Int8 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
i64, err := strconv.ParseInt(data.(string), 0, 8)
|
||||
return int8(i64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToUint8HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to uint8.
|
||||
func StringToUint8HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Uint8 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u64, err := strconv.ParseUint(data.(string), 0, 8)
|
||||
return uint8(u64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToInt16HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to int16.
|
||||
func StringToInt16HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Int16 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
i64, err := strconv.ParseInt(data.(string), 0, 16)
|
||||
return int16(i64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToUint16HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to uint16.
|
||||
func StringToUint16HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Uint16 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u64, err := strconv.ParseUint(data.(string), 0, 16)
|
||||
return uint16(u64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToInt32HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to int32.
|
||||
func StringToInt32HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Int32 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
i64, err := strconv.ParseInt(data.(string), 0, 32)
|
||||
return int32(i64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToUint32HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to uint32.
|
||||
func StringToUint32HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Uint32 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u64, err := strconv.ParseUint(data.(string), 0, 32)
|
||||
return uint32(u64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToInt64HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to int64.
|
||||
func StringToInt64HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Int64 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
i64, err := strconv.ParseInt(data.(string), 0, 64)
|
||||
return int64(i64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToUint64HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to uint64.
|
||||
func StringToUint64HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Uint64 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u64, err := strconv.ParseUint(data.(string), 0, 64)
|
||||
return uint64(u64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToIntHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to int.
|
||||
func StringToIntHookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Int {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
i64, err := strconv.ParseInt(data.(string), 0, 0)
|
||||
return int(i64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToUintHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to uint.
|
||||
func StringToUintHookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Uint {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
u64, err := strconv.ParseUint(data.(string), 0, 0)
|
||||
return uint(u64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToFloat32HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to float32.
|
||||
func StringToFloat32HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Float32 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
f64, err := strconv.ParseFloat(data.(string), 32)
|
||||
return float32(f64), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToFloat64HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to float64.
|
||||
func StringToFloat64HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Float64 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
f64, err := strconv.ParseFloat(data.(string), 64)
|
||||
return f64, wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToBoolHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to bool.
|
||||
func StringToBoolHookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Bool {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
b, err := strconv.ParseBool(data.(string))
|
||||
return b, wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToByteHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to byte.
|
||||
func StringToByteHookFunc() DecodeHookFunc {
|
||||
return StringToUint8HookFunc()
|
||||
}
|
||||
|
||||
// StringToRuneHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to rune.
|
||||
func StringToRuneHookFunc() DecodeHookFunc {
|
||||
return StringToInt32HookFunc()
|
||||
}
|
||||
|
||||
// StringToComplex64HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to complex64.
|
||||
func StringToComplex64HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Complex64 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
c128, err := strconv.ParseComplex(data.(string), 64)
|
||||
return complex64(c128), wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToComplex128HookFunc returns a DecodeHookFunc that converts
|
||||
// strings to complex128.
|
||||
func StringToComplex128HookFunc() DecodeHookFunc {
|
||||
return func(f reflect.Type, t reflect.Type, data any) (any, error) {
|
||||
if f.Kind() != reflect.String || t.Kind() != reflect.Complex128 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
c128, err := strconv.ParseComplex(data.(string), 128)
|
||||
return c128, wrapStrconvNumError(err)
|
||||
}
|
||||
}
|
||||
244
vendor/github.com/go-viper/mapstructure/v2/errors.go
generated
vendored
Normal file
244
vendor/github.com/go-viper/mapstructure/v2/errors.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
package mapstructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Error interface is implemented by all errors emitted by mapstructure.
|
||||
//
|
||||
// Use [errors.As] to check if an error implements this interface.
|
||||
type Error interface {
|
||||
error
|
||||
|
||||
mapstructure()
|
||||
}
|
||||
|
||||
// DecodeError is a generic error type that holds information about
|
||||
// a decoding error together with the name of the field that caused the error.
|
||||
type DecodeError struct {
|
||||
name string
|
||||
err error
|
||||
}
|
||||
|
||||
func newDecodeError(name string, err error) *DecodeError {
|
||||
return &DecodeError{
|
||||
name: name,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *DecodeError) Name() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e *DecodeError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *DecodeError) Error() string {
|
||||
return fmt.Sprintf("'%s' %s", e.name, e.err)
|
||||
}
|
||||
|
||||
func (*DecodeError) mapstructure() {}
|
||||
|
||||
// ParseError is an error type that indicates a value could not be parsed
|
||||
// into the expected type.
|
||||
type ParseError struct {
|
||||
Expected reflect.Value
|
||||
Value any
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *ParseError) Error() string {
|
||||
return fmt.Sprintf("cannot parse value as '%s': %s", e.Expected.Type(), e.Err)
|
||||
}
|
||||
|
||||
func (*ParseError) mapstructure() {}
|
||||
|
||||
// UnconvertibleTypeError is an error type that indicates a value could not be
|
||||
// converted to the expected type.
|
||||
type UnconvertibleTypeError struct {
|
||||
Expected reflect.Value
|
||||
Value any
|
||||
}
|
||||
|
||||
func (e *UnconvertibleTypeError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"expected type '%s', got unconvertible type '%s'",
|
||||
e.Expected.Type(),
|
||||
reflect.TypeOf(e.Value),
|
||||
)
|
||||
}
|
||||
|
||||
func (*UnconvertibleTypeError) mapstructure() {}
|
||||
|
||||
func wrapStrconvNumError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err, ok := err.(*strconv.NumError); ok {
|
||||
return &strconvNumError{Err: err}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type strconvNumError struct {
|
||||
Err *strconv.NumError
|
||||
}
|
||||
|
||||
func (e *strconvNumError) Error() string {
|
||||
return "strconv." + e.Err.Func + ": " + e.Err.Err.Error()
|
||||
}
|
||||
|
||||
func (e *strconvNumError) Unwrap() error { return e.Err }
|
||||
|
||||
func wrapUrlError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err, ok := err.(*url.Error); ok {
|
||||
return &urlError{Err: err}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type urlError struct {
|
||||
Err *url.Error
|
||||
}
|
||||
|
||||
func (e *urlError) Error() string {
|
||||
return fmt.Sprintf("%s", e.Err.Err)
|
||||
}
|
||||
|
||||
func (e *urlError) Unwrap() error { return e.Err }
|
||||
|
||||
func wrapNetParseError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err, ok := err.(*net.ParseError); ok {
|
||||
return &netParseError{Err: err}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type netParseError struct {
|
||||
Err *net.ParseError
|
||||
}
|
||||
|
||||
func (e *netParseError) Error() string {
|
||||
return "invalid " + e.Err.Type
|
||||
}
|
||||
|
||||
func (e *netParseError) Unwrap() error { return e.Err }
|
||||
|
||||
func wrapTimeParseError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err, ok := err.(*time.ParseError); ok {
|
||||
return &timeParseError{Err: err}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type timeParseError struct {
|
||||
Err *time.ParseError
|
||||
}
|
||||
|
||||
func (e *timeParseError) Error() string {
|
||||
if e.Err.Message == "" {
|
||||
return fmt.Sprintf("parsing time as %q: cannot parse as %q", e.Err.Layout, e.Err.LayoutElem)
|
||||
}
|
||||
|
||||
return "parsing time " + e.Err.Message
|
||||
}
|
||||
|
||||
func (e *timeParseError) Unwrap() error { return e.Err }
|
||||
|
||||
func wrapNetIPParseAddrError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if errMsg := err.Error(); strings.HasPrefix(errMsg, "ParseAddr") {
|
||||
errPieces := strings.Split(errMsg, ": ")
|
||||
|
||||
return fmt.Errorf("ParseAddr: %s", errPieces[len(errPieces)-1])
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func wrapNetIPParseAddrPortError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errMsg := err.Error()
|
||||
if strings.HasPrefix(errMsg, "invalid port ") {
|
||||
return errors.New("invalid port")
|
||||
} else if strings.HasPrefix(errMsg, "invalid ip:port ") {
|
||||
return errors.New("invalid ip:port")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func wrapNetIPParsePrefixError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if errMsg := err.Error(); strings.HasPrefix(errMsg, "netip.ParsePrefix") {
|
||||
errPieces := strings.Split(errMsg, ": ")
|
||||
|
||||
return fmt.Errorf("netip.ParsePrefix: %s", errPieces[len(errPieces)-1])
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func wrapTimeParseDurationError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errMsg := err.Error()
|
||||
if strings.HasPrefix(errMsg, "time: unknown unit ") {
|
||||
return errors.New("time: unknown unit")
|
||||
} else if strings.HasPrefix(errMsg, "time: ") {
|
||||
idx := strings.LastIndex(errMsg, " ")
|
||||
|
||||
return errors.New(errMsg[:idx])
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func wrapTimeParseLocationError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errMsg := err.Error()
|
||||
if strings.Contains(errMsg, "unknown time zone") || strings.HasPrefix(errMsg, "time: unknown format") {
|
||||
return fmt.Errorf("invalid time zone format: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
294
vendor/github.com/go-viper/mapstructure/v2/flake.lock
generated
vendored
Normal file
294
vendor/github.com/go-viper/mapstructure/v2/flake.lock
generated
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
{
|
||||
"nodes": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"git-hooks": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742042642,
|
||||
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "latest",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat",
|
||||
"git-hooks": "git-hooks",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744876578,
|
||||
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743550720,
|
||||
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742649964,
|
||||
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-parts": "flake-parts",
|
||||
"libgit2": "libgit2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-23-11": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs-regression": [
|
||||
"devenv"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741798497,
|
||||
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.24",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1733212471,
|
||||
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1743296961,
|
||||
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1717432640,
|
||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1733477122,
|
||||
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1744536153,
|
||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"flake-parts": "flake-parts_2",
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
46
vendor/github.com/go-viper/mapstructure/v2/flake.nix
generated
vendored
Normal file
46
vendor/github.com/go-viper/mapstructure/v2/flake.nix
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
inputs.devenv.flakeModule
|
||||
];
|
||||
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
rec {
|
||||
devenv.shells = {
|
||||
default = {
|
||||
languages = {
|
||||
go.enable = true;
|
||||
};
|
||||
|
||||
pre-commit.hooks = {
|
||||
nixpkgs-fmt.enable = true;
|
||||
};
|
||||
|
||||
packages = with pkgs; [
|
||||
golangci-lint
|
||||
];
|
||||
|
||||
# https://github.com/cachix/devenv/issues/528#issuecomment-1556108767
|
||||
containers = pkgs.lib.mkForce { };
|
||||
};
|
||||
|
||||
ci = devenv.shells.default;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
11
vendor/github.com/go-viper/mapstructure/v2/internal/errors/errors.go
generated
vendored
Normal file
11
vendor/github.com/go-viper/mapstructure/v2/internal/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package errors
|
||||
|
||||
import "errors"
|
||||
|
||||
func New(text string) error {
|
||||
return errors.New(text)
|
||||
}
|
||||
|
||||
func As(err error, target interface{}) bool {
|
||||
return errors.As(err, target)
|
||||
}
|
||||
9
vendor/github.com/go-viper/mapstructure/v2/internal/errors/join.go
generated
vendored
Normal file
9
vendor/github.com/go-viper/mapstructure/v2/internal/errors/join.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build go1.20
|
||||
|
||||
package errors
|
||||
|
||||
import "errors"
|
||||
|
||||
func Join(errs ...error) error {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
61
vendor/github.com/go-viper/mapstructure/v2/internal/errors/join_go1_19.go
generated
vendored
Normal file
61
vendor/github.com/go-viper/mapstructure/v2/internal/errors/join_go1_19.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
//go:build !go1.20
|
||||
|
||||
// Copyright 2022 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 errors
|
||||
|
||||
// Join returns an error that wraps the given errors.
|
||||
// Any nil error values are discarded.
|
||||
// Join returns nil if every value in errs is nil.
|
||||
// The error formats as the concatenation of the strings obtained
|
||||
// by calling the Error method of each element of errs, with a newline
|
||||
// between each string.
|
||||
//
|
||||
// A non-nil error returned by Join implements the Unwrap() []error method.
|
||||
func Join(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &joinError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type joinError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *joinError) Error() string {
|
||||
// Since Join returns nil if every value in errs is nil,
|
||||
// e.errs cannot be empty.
|
||||
if len(e.errs) == 1 {
|
||||
return e.errs[0].Error()
|
||||
}
|
||||
|
||||
b := []byte(e.errs[0].Error())
|
||||
for _, err := range e.errs[1:] {
|
||||
b = append(b, '\n')
|
||||
b = append(b, err.Error()...)
|
||||
}
|
||||
// At this point, b has at least one byte '\n'.
|
||||
// return unsafe.String(&b[0], len(b))
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (e *joinError) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
1712
vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
generated
vendored
Normal file
1712
vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
44
vendor/github.com/go-viper/mapstructure/v2/reflect_go1_19.go
generated
vendored
Normal file
44
vendor/github.com/go-viper/mapstructure/v2/reflect_go1_19.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//go:build !go1.20
|
||||
|
||||
package mapstructure
|
||||
|
||||
import "reflect"
|
||||
|
||||
func isComparable(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
switch k {
|
||||
case reflect.Invalid:
|
||||
return false
|
||||
|
||||
case reflect.Array:
|
||||
switch v.Type().Elem().Kind() {
|
||||
case reflect.Interface, reflect.Array, reflect.Struct:
|
||||
for i := 0; i < v.Type().Len(); i++ {
|
||||
// if !v.Index(i).Comparable() {
|
||||
if !isComparable(v.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return v.Type().Comparable()
|
||||
|
||||
case reflect.Interface:
|
||||
// return v.Elem().Comparable()
|
||||
return isComparable(v.Elem())
|
||||
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
return false
|
||||
|
||||
// if !v.Field(i).Comparable() {
|
||||
if !isComparable(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
default:
|
||||
return v.Type().Comparable()
|
||||
}
|
||||
}
|
||||
10
vendor/github.com/go-viper/mapstructure/v2/reflect_go1_20.go
generated
vendored
Normal file
10
vendor/github.com/go-viper/mapstructure/v2/reflect_go1_20.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build go1.20
|
||||
|
||||
package mapstructure
|
||||
|
||||
import "reflect"
|
||||
|
||||
// TODO: remove once we drop support for Go <1.20
|
||||
func isComparable(v reflect.Value) bool {
|
||||
return v.Comparable()
|
||||
}
|
||||
20
vendor/github.com/gookit/color/.gitignore
generated
vendored
20
vendor/github.com/gookit/color/.gitignore
generated
vendored
@@ -1,20 +0,0 @@
|
||||
*.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
vendor/github.com/gookit/color/.nojekyll
generated
vendored
0
vendor/github.com/gookit/color/.nojekyll
generated
vendored
20
vendor/github.com/gookit/color/LICENSE
generated
vendored
20
vendor/github.com/gookit/color/LICENSE
generated
vendored
@@ -1,20 +0,0 @@
|
||||
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.
|
||||
580
vendor/github.com/gookit/color/README.md
generated
vendored
580
vendor/github.com/gookit/color/README.md
generated
vendored
@@ -1,580 +0,0 @@
|
||||
# CLI Color
|
||||
|
||||

|
||||
[](https://github.com/gookit/color/actions)
|
||||
[](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/color&utm_campaign=Badge_Grade)
|
||||
[](https://pkg.go.dev/github.com/gookit/color?tab=overview)
|
||||
[](https://github.com/gookit/color)
|
||||
[](https://travis-ci.org/gookit/color)
|
||||
[](https://coveralls.io/github/gookit/color?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/gookit/color)
|
||||
|
||||
A command-line color library with 16/256/True color support, universal API methods and Windows support.
|
||||
|
||||
> **[中文说明](README.zh-CN.md)**
|
||||
|
||||
Basic color preview:
|
||||
|
||||

|
||||
|
||||
Now, 256 colors and RGB colors have also been supported to work in Windows CMD and PowerShell:
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
- Support converts `HEX` `HSL` value to RGB color
|
||||
- Generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
|
||||
- Supports HTML tag-style color rendering, such as `<green>message</> <fg=red;bg=blue>text</>`.
|
||||
- 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`
|
||||
|
||||

|
||||
|
||||
## Basic/16 color
|
||||
|
||||
Supported on any Windows version. Provide generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
|
||||
|
||||
```go
|
||||
color.Bold.Println("bold 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`
|
||||
|
||||

|
||||
|
||||
### 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.Notice.Println("Notice message")
|
||||
color.Error.Println("Error message")
|
||||
// ...
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_basic.go`
|
||||
|
||||

|
||||
|
||||
**Tips style**
|
||||
|
||||
```go
|
||||
color.Info.Tips("Info tips message")
|
||||
color.Notice.Tips("Notice tips message")
|
||||
color.Error.Tips("Error tips message")
|
||||
color.Secondary.Tips("Secondary tips message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_tips.go`
|
||||
|
||||

|
||||
|
||||
**Prompt Style**
|
||||
|
||||
```go
|
||||
color.Info.Prompt("Info prompt message")
|
||||
color.Notice.Prompt("Notice prompt message")
|
||||
color.Error.Prompt("Error prompt message")
|
||||
// ...
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_prompt.go`
|
||||
|
||||

|
||||
|
||||
**Block Style**
|
||||
|
||||
```go
|
||||
color.Danger.Block("Danger block message")
|
||||
color.Warn.Block("Warn block message")
|
||||
// ...
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_block.go`
|
||||
|
||||

|
||||
|
||||
## 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`
|
||||
|
||||

|
||||
|
||||
## 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`
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||
`Print,Printf,Println` functions support auto parse and render color tags.
|
||||
|
||||
```go
|
||||
text := `
|
||||
<mga1>gookit/color:</>
|
||||
A <green>command-line</>
|
||||
<cyan>color library</> with <fg=167;bg=232>256-color</>
|
||||
and <fg=11aa23;op=bold>True-color</> support,
|
||||
<fg=mga;op=i>universal API</> methods
|
||||
and <cyan>Windows</> support.
|
||||
`
|
||||
color.Print(text)
|
||||
```
|
||||
|
||||
Preview, code please see [_examples/demo_tag.go](_examples/demo_tag.go):
|
||||
|
||||

|
||||
|
||||
**Tag formats:**
|
||||
|
||||
- Use built in tags: `<TAG_NAME>CONTENT</>` e.g: `<info>message</>`
|
||||
- Custom tag attributes: `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>` e.g: `<fg=167;bg=232>wel</>`
|
||||
|
||||
> **Supported** on Windows `cmd.exe` `PowerShell`.
|
||||
|
||||
Examples:
|
||||
|
||||
```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</>")
|
||||
```
|
||||
|
||||
### Tag attributes
|
||||
|
||||
tag attributes format:
|
||||
|
||||
```text
|
||||
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"
|
||||
```
|
||||
|
||||
> tag attributes parse please see `func ParseCodeFromAttr()`
|
||||
|
||||
### Built-in tags
|
||||
|
||||
Built-in tags please see var `colorTags` in [color_tag.go](color_tag.go)
|
||||
|
||||
```go
|
||||
// use style tag
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
|
||||
color.Println("<suc>hello</>")
|
||||
color.Println("<error>hello</>")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/color_tag.go`
|
||||
|
||||

|
||||
|
||||
**Use `color.Tag` build message**:
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
## 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")
|
||||
```
|
||||
|
||||
### Convert utils
|
||||
|
||||
`color` has many built-in color conversion utility functions.
|
||||
|
||||
```go
|
||||
func Basic2hex(val uint8) string
|
||||
|
||||
func Bg2Fg(val uint8) uint8
|
||||
func Fg2Bg(val uint8) uint8
|
||||
|
||||
func C256ToRgb(val uint8) (rgb []uint8)
|
||||
func C256ToRgbV1(val uint8) (rgb []uint8)
|
||||
|
||||
func Hex2basic(hex string, asBg ...bool) uint8
|
||||
func Hex2rgb(hex string) []int
|
||||
func HexToRGB(hex string) []int
|
||||
func HexToRgb(hex string) (rgb []int)
|
||||
|
||||
func HslIntToRgb(h, s, l int) (rgb []uint8)
|
||||
func HslToRgb(h, s, l float64) (rgb []uint8)
|
||||
func HsvToRgb(h, s, v int) (rgb []uint8)
|
||||
|
||||
func Rgb2ansi(r, g, b uint8, isBg bool) uint8
|
||||
func Rgb2basic(r, g, b uint8, isBg bool) uint8
|
||||
func Rgb2hex(rgb []int) string
|
||||
func Rgb2short(r, g, b uint8) uint8
|
||||
func RgbTo256(r, g, b uint8) uint8
|
||||
func RgbTo256Table() map[string]uint8
|
||||
func RgbToAnsi(r, g, b uint8, isBg bool) uint8
|
||||
func RgbToHex(rgb []int) string
|
||||
func RgbToHsl(r, g, b uint8) []float64
|
||||
func RgbToHslInt(r, g, b uint8) []int
|
||||
```
|
||||
|
||||
**Convert to `RGBColor`**:
|
||||
|
||||
- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
|
||||
- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
|
||||
- `func HEX(hex string, isBg ...bool) RGBColor`
|
||||
- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
|
||||
- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
|
||||
|
||||
## Util functions
|
||||
|
||||
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
|
||||
|
||||
> More useful func please see https://pkg.go.dev/github.com/gookit/color
|
||||
|
||||
### Detect color level
|
||||
|
||||
`color` automatically checks the color levels supported by the current environment.
|
||||
|
||||
```go
|
||||
// Level is the color level supported by a terminal.
|
||||
type Level = terminfo.ColorLevel
|
||||
|
||||
// terminal color available level alias of the terminfo.ColorLevel*
|
||||
const (
|
||||
LevelNo = terminfo.ColorLevelNone // not support color.
|
||||
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
|
||||
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
|
||||
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
|
||||
)
|
||||
```
|
||||
|
||||
- `func SupportColor() bool` Whether the current environment supports color output
|
||||
- `func Support256Color() bool` Whether the current environment supports 256-color output
|
||||
- `func SupportTrueColor() bool` Whether the current environment supports (RGB)True-color output
|
||||
- `func TermColorLevel() Level` Get the currently supported color level
|
||||
|
||||
|
||||
## Projects using color
|
||||
|
||||
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
|
||||
- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的(中)后台系统框架
|
||||
- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
|
||||
- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
|
||||
- https://github.com/olivia-ai/olivia 💁♀️Your new best friend powered by an artificial neural network
|
||||
- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
|
||||
- https://github.com/securego/gosec Golang security checker
|
||||
- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
|
||||
- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
|
||||
|
||||
## 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)
|
||||
- [muesli/termenv](https://github.com/muesli/termenv)
|
||||
- [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)
|
||||
591
vendor/github.com/gookit/color/README.zh-CN.md
generated
vendored
591
vendor/github.com/gookit/color/README.zh-CN.md
generated
vendored
@@ -1,591 +0,0 @@
|
||||
# CLI Color
|
||||
|
||||

|
||||
[](https://github.com/gookit/color/actions)
|
||||
[](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/color&utm_campaign=Badge_Grade)
|
||||
[](https://pkg.go.dev/github.com/gookit/color?tab=overview)
|
||||
[](https://github.com/gookit/color)
|
||||
[](https://travis-ci.org/gookit/color)
|
||||
[](https://coveralls.io/github/gookit/color?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/gookit/color)
|
||||
|
||||
Golang下的命令行色彩使用库, 拥有丰富的色彩(16/256/True)渲染输出,通用的API方法,兼容Windows系统
|
||||
|
||||
> **[EN README](README.md)**
|
||||
|
||||
基本颜色预览:
|
||||
|
||||

|
||||
|
||||
现在,256色和RGB色彩也已经支持windows CMD和PowerShell中工作:
|
||||
|
||||

|
||||
|
||||
## 功能特色
|
||||
|
||||
- 使用简单方便
|
||||
- 支持丰富的颜色输出, 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色彩的终端
|
||||
- 支持转换 `HEX` `HSL` 等为RGB色彩
|
||||
- 提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
|
||||
- 同时支持html标签式的颜色渲染,除了使用内置标签,同时支持自定义颜色属性
|
||||
- 例如: `this an <green>message</> <fg=red;bg=blue>text</>` 标签内部文本将会渲染对应色彩
|
||||
- 自定义颜色属性: 支持使用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`
|
||||
|
||||

|
||||
|
||||
## 基础颜色(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")
|
||||
// ...
|
||||
|
||||
// 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`
|
||||
|
||||

|
||||
|
||||
### 构建风格
|
||||
|
||||
```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")
|
||||
// ...
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_basic.go`
|
||||
|
||||

|
||||
|
||||
**简约提示风格**
|
||||
|
||||
```go
|
||||
color.Info.Tips("Info tips message")
|
||||
color.Notice.Tips("Notice tips message")
|
||||
color.Error.Tips("Error tips message")
|
||||
// ...
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_tips.go`
|
||||
|
||||

|
||||
|
||||
**着重提示风格**
|
||||
|
||||
```go
|
||||
color.Info.Prompt("Info prompt message")
|
||||
color.Error.Prompt("Error prompt message")
|
||||
color.Danger.Prompt("Danger prompt message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_prompt.go`
|
||||
|
||||

|
||||
|
||||
**强调提示风格**
|
||||
|
||||
```go
|
||||
color.Warn.Block("Warn block message")
|
||||
color.Debug.Block("Debug block message")
|
||||
color.Question.Block("Question block message")
|
||||
```
|
||||
|
||||
Run demo: `go run ./_examples/theme_block.go`
|
||||
|
||||

|
||||
|
||||
## 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`
|
||||
|
||||

|
||||
|
||||
## RGB/True色彩使用
|
||||
|
||||
> RGB色彩在 `v1.2.4` 后支持 Windows `CMD`, `PowerShell` 环境
|
||||
|
||||
**效果预览:**
|
||||
|
||||
> 运行 demo: `Run demo: go run ./_examples/color_rgb.go`
|
||||
|
||||

|
||||
|
||||
代码示例:
|
||||
|
||||
```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风格
|
||||
|
||||
> TIP: 可同时设置前景和背景色
|
||||
|
||||
- `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")
|
||||
```
|
||||
|
||||
## 使用颜色标签
|
||||
|
||||
`Print,Printf,Println` 等方法支持自动解析并渲染 HTML 风格的颜色标签
|
||||
|
||||
> **支持** 在windows `cmd.exe` `PowerShell` 使用
|
||||
|
||||
简单示例:
|
||||
|
||||
```go
|
||||
text := `
|
||||
<mga1>gookit/color:</>
|
||||
A <green>command-line</>
|
||||
<cyan>color library</> with <fg=167;bg=232>256-color</>
|
||||
and <fg=11aa23;op=bold>True-color</> support,
|
||||
<fg=mga;op=i>universal API</> methods
|
||||
and <cyan>Windows</> support.
|
||||
`
|
||||
color.Print(text)
|
||||
```
|
||||
|
||||
输出效果, 示例代码请看 [_examples/demo_tag.go](_examples/demo_tag.go):
|
||||
|
||||

|
||||
|
||||
**颜色标签格式:**
|
||||
|
||||
- 直接使用内置风格标签: `<TAG_NAME>CONTENT</>` e.g: `<info>message</>`
|
||||
- 自定义标签属性: `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>` e.g: `<fg=167;bg=232>wel</>`
|
||||
|
||||
使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式
|
||||
|
||||
> 同时支持自定义颜色属性: 支持使用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</>")
|
||||
```
|
||||
|
||||
### 自定义标签属性
|
||||
|
||||
标签属性格式:
|
||||
|
||||
```text
|
||||
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"
|
||||
```
|
||||
|
||||
> tag attributes parse please see `func ParseCodeFromAttr()`
|
||||
|
||||
### 内置标签
|
||||
|
||||
内置标签请参见变量 `colorTags` 定义, 源文件 [color_tag.go](color_tag.go)
|
||||
|
||||
```go
|
||||
// use style tag
|
||||
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
|
||||
color.Println("<suc>hello</>")
|
||||
color.Println("<error>hello</>")
|
||||
```
|
||||
|
||||
> 运行 demo: `go run ./_examples/color_tag.go`
|
||||
|
||||

|
||||
|
||||
**使用 `color.Tag` 包装标签**:
|
||||
|
||||
可以使用通用的输出API方法,给后面输出的文本信息加上给定的颜色风格标签
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
## 颜色转换
|
||||
|
||||
支持 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")
|
||||
```
|
||||
|
||||
### 颜色转换方法
|
||||
|
||||
`color` 内置了许多颜色转换工具方法
|
||||
|
||||
```go
|
||||
func Basic2hex(val uint8) string
|
||||
|
||||
func Bg2Fg(val uint8) uint8
|
||||
func Fg2Bg(val uint8) uint8
|
||||
|
||||
func C256ToRgb(val uint8) (rgb []uint8)
|
||||
func C256ToRgbV1(val uint8) (rgb []uint8)
|
||||
|
||||
func Hex2basic(hex string, asBg ...bool) uint8
|
||||
func Hex2rgb(hex string) []int
|
||||
func HexToRGB(hex string) []int
|
||||
func HexToRgb(hex string) (rgb []int)
|
||||
|
||||
func HslIntToRgb(h, s, l int) (rgb []uint8)
|
||||
func HslToRgb(h, s, l float64) (rgb []uint8)
|
||||
func HsvToRgb(h, s, v int) (rgb []uint8)
|
||||
|
||||
func Rgb2ansi(r, g, b uint8, isBg bool) uint8
|
||||
func Rgb2basic(r, g, b uint8, isBg bool) uint8
|
||||
func Rgb2hex(rgb []int) string
|
||||
func Rgb2short(r, g, b uint8) uint8
|
||||
func RgbTo256(r, g, b uint8) uint8
|
||||
func RgbTo256Table() map[string]uint8
|
||||
func RgbToAnsi(r, g, b uint8, isBg bool) uint8
|
||||
func RgbToHex(rgb []int) string
|
||||
func RgbToHsl(r, g, b uint8) []float64
|
||||
func RgbToHslInt(r, g, b uint8) []int
|
||||
```
|
||||
|
||||
**转换为 `RGBColor`**:
|
||||
|
||||
- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
|
||||
- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
|
||||
- `func HEX(hex string, isBg ...bool) RGBColor`
|
||||
- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
|
||||
- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
|
||||
|
||||
## 工具方法参考
|
||||
|
||||
一些有用的工具方法参考
|
||||
|
||||
- `Disable()` 禁用颜色渲染输出
|
||||
- `SetOutput(io.Writer)` 自定义设置渲染后的彩色文本输出位置
|
||||
- `ForceOpenColor()` 强制开启颜色渲染
|
||||
- `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
|
||||
- 更多请查看文档 https://pkg.go.dev/github.com/gookit/color
|
||||
|
||||
### 检测支持的颜色级别
|
||||
|
||||
`color` 会自动检查当前环境支持的颜色级别
|
||||
|
||||
```go
|
||||
// Level is the color level supported by a terminal.
|
||||
type Level = terminfo.ColorLevel
|
||||
|
||||
// terminal color available level alias of the terminfo.ColorLevel*
|
||||
const (
|
||||
LevelNo = terminfo.ColorLevelNone // not support color.
|
||||
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
|
||||
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
|
||||
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
|
||||
)
|
||||
```
|
||||
|
||||
- `func SupportColor() bool` 当前环境是否支持色彩输出
|
||||
- `func Support256Color() bool` 当前环境是否支持256色彩输出
|
||||
- `func SupportTrueColor() bool` 当前环境是否支持(RGB)True色彩输出
|
||||
- `func TermColorLevel() Level` 获取当前支持的颜色级别
|
||||
|
||||
## 使用Color的项目
|
||||
|
||||
看看这些使用了 https://github.com/gookit/color 的项目:
|
||||
|
||||
- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
|
||||
- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的(中)后台系统框架
|
||||
- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
|
||||
- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
|
||||
- https://github.com/olivia-ai/olivia 💁♀️Your new best friend powered by an artificial neural network
|
||||
- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
|
||||
- https://github.com/securego/gosec Golang security checker
|
||||
- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
|
||||
- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
|
||||
|
||||
## 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)
|
||||
- [muesli/termenv](https://github.com/muesli/termenv)
|
||||
- [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
|
||||
6
vendor/github.com/gookit/color/any.go
generated
vendored
6
vendor/github.com/gookit/color/any.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package color
|
||||
|
||||
type any = interface{}
|
||||
251
vendor/github.com/gookit/color/color.go
generated
vendored
251
vendor/github.com/gookit/color/color.go
generated
vendored
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
// color render templates
|
||||
//
|
||||
// ESC 操作的表示:
|
||||
//
|
||||
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
|
||||
const (
|
||||
// StartSet chars
|
||||
StartSet = "\x1b["
|
||||
// ResetSet close all properties.
|
||||
ResetSet = "\x1b[0m"
|
||||
// SettingTpl string.
|
||||
SettingTpl = "\x1b[%sm"
|
||||
// FullColorTpl for build color code
|
||||
FullColorTpl = "\x1b[%sm%s\x1b[0m"
|
||||
// CodeSuffix string for color code.
|
||||
CodeSuffix = "[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 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 Get the currently supported color level
|
||||
func TermColorLevel() Level {
|
||||
return colorLevel
|
||||
}
|
||||
|
||||
// SupportColor Whether the current environment supports color output
|
||||
func SupportColor() bool {
|
||||
return colorLevel > terminfo.ColorLevelNone
|
||||
}
|
||||
|
||||
// Support16Color on the current ENV
|
||||
// func Support16Color() bool {
|
||||
// return colorLevel > terminfo.ColorLevelNone
|
||||
// }
|
||||
|
||||
// Support256Color Whether the current environment supports 256-color output
|
||||
func Support256Color() bool {
|
||||
return colorLevel > terminfo.ColorLevelBasic
|
||||
}
|
||||
|
||||
// SupportTrueColor Whether the current environment supports (RGB)True-color output
|
||||
func SupportTrueColor() bool {
|
||||
return colorLevel > terminfo.ColorLevelHundreds
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* global settings
|
||||
*************************************************************/
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// ForceSetColorLevel 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: please don't use
|
||||
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 ...any) 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)
|
||||
return StartSet + code + "m" + message + ResetSet
|
||||
}
|
||||
|
||||
// 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 ...any) string {
|
||||
msg := formatArgsForPrintln(args)
|
||||
if len(code) == 0 {
|
||||
return msg
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !Enable || !SupportColor() {
|
||||
return ClearCode(msg)
|
||||
}
|
||||
|
||||
return StartSet + code + "m" + msg + ResetSet
|
||||
}
|
||||
|
||||
// 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)
|
||||
return StartSet + code + "m" + str + ResetSet
|
||||
}
|
||||
|
||||
// ClearCode clear color codes.
|
||||
//
|
||||
// eg:
|
||||
//
|
||||
// "\033[36;1mText\x1b[0m" -> "Text"
|
||||
func ClearCode(str string) string {
|
||||
if !strings.Contains(str, CodeSuffix) {
|
||||
return str
|
||||
}
|
||||
return codeRegex.ReplaceAllString(str, "")
|
||||
}
|
||||
303
vendor/github.com/gookit/color/color_256.go
generated
vendored
303
vendor/github.com/gookit/color/color_256.go
generated
vendored
@@ -1,303 +0,0 @@
|
||||
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.
|
||||
// Support 256 color on windows CMD, PowerShell
|
||||
//
|
||||
// 颜色值使用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]
|
||||
//
|
||||
// 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 ...any) {
|
||||
doPrintV2(c.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (c Color256) Printf(format string, a ...any) {
|
||||
doPrintV2(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (c Color256) Println(a ...any) {
|
||||
doPrintlnV2(c.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (c Color256) Sprint(a ...any) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (c Color256) Sprintf(format string, a ...any) 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 Fg256Pfx + strconv.Itoa(int(c[0]))
|
||||
}
|
||||
|
||||
if c[1] == AsBg { // 1 is Bg
|
||||
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 {
|
||||
// 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 ...any) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (s *Style256) Printf(format string, a ...any) {
|
||||
doPrintV2(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (s *Style256) Println(a ...any) {
|
||||
doPrintlnV2(s.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (s *Style256) Sprint(a ...any) string {
|
||||
return RenderCode(s.Code(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (s *Style256) Sprintf(format string, a ...any) 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, Fg256Pfx+strconv.FormatInt(int64(s.fg[0]), 10))
|
||||
}
|
||||
|
||||
if s.bg[1] > 0 {
|
||||
ss = append(ss, Bg256Pfx+strconv.FormatInt(int64(s.bg[0]), 10))
|
||||
}
|
||||
|
||||
if s.opts.IsValid() {
|
||||
ss = append(ss, s.opts.String())
|
||||
}
|
||||
return strings.Join(ss, ";")
|
||||
}
|
||||
443
vendor/github.com/gookit/color/color_rgb.go
generated
vendored
443
vendor/github.com/gookit/color/color_rgb.go
generated
vendored
@@ -1,443 +0,0 @@
|
||||
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
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* RGB Color(Bit24Color, TrueColor)
|
||||
*************************************************************/
|
||||
|
||||
// RGBColor definition.
|
||||
// Support RGB color on Windows CMD, PowerShell
|
||||
//
|
||||
// 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}
|
||||
type RGBColor [4]uint8
|
||||
|
||||
// create an 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...) }
|
||||
|
||||
// RgbFromInt create instance from int r,g,b value
|
||||
func RgbFromInt(r, g, b int, isBg ...bool) RGBColor {
|
||||
return RGB(uint8(r), uint8(g), uint8(b), isBg...)
|
||||
}
|
||||
|
||||
// RgbFromInts create instance from []int r,g,b value
|
||||
func RgbFromInts(rgb []int, isBg ...bool) RGBColor {
|
||||
return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(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...) }
|
||||
|
||||
// RGBFromHEX quick RGBColor from hex string, alias of HEX()
|
||||
func RGBFromHEX(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
|
||||
|
||||
// HSL create RGB color from a hsl value.
|
||||
// more see HslToRgb()
|
||||
func HSL(h, s, l float64, isBg ...bool) RGBColor {
|
||||
rgb := HslToRgb(h, s, l)
|
||||
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
|
||||
}
|
||||
|
||||
// Hsl alias of the HSL()
|
||||
func Hsl(h, s, l float64, isBg ...bool) RGBColor { return HSL(h, s, l, isBg...) }
|
||||
|
||||
// HSLInt create RGB color from a hsl int value.
|
||||
// more see HslIntToRgb()
|
||||
func HSLInt(h, s, l int, isBg ...bool) RGBColor {
|
||||
rgb := HslIntToRgb(h, s, l)
|
||||
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
|
||||
}
|
||||
|
||||
// HslInt alias of the HSLInt()
|
||||
func HslInt(h, s, l int, isBg ...bool) RGBColor { return HSLInt(h, s, l, isBg...) }
|
||||
|
||||
// RGBFromSlice quick RGBColor from slice
|
||||
func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
|
||||
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
|
||||
}
|
||||
|
||||
// RGBFromString create RGB color from a string.
|
||||
// Support use color name in the {namedRgbMap}
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// c := RGBFromString("170,187,204")
|
||||
// c.Print("message")
|
||||
//
|
||||
// c := RGBFromString("brown")
|
||||
// c.Print("message with color brown")
|
||||
func RGBFromString(rgb string, isBg ...bool) RGBColor {
|
||||
// use color name in the {namedRgbMap}
|
||||
if rgbVal, ok := namedRgbMap[rgb]; ok {
|
||||
rgb = rgbVal
|
||||
}
|
||||
|
||||
// use rgb string.
|
||||
ss := stringToArr(rgb, ",")
|
||||
if len(ss) != 3 {
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
var ar [3]uint8
|
||||
for i, val := range ss {
|
||||
iv, err := strconv.Atoi(val)
|
||||
if err != nil || !isValidUint8(iv) {
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
ar[i] = uint8(iv)
|
||||
}
|
||||
|
||||
return RGB(ar[0], ar[1], 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 ...any) {
|
||||
doPrintV2(c.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (c RGBColor) Printf(format string, a ...any) {
|
||||
doPrintV2(c.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (c RGBColor) Println(a ...any) {
|
||||
doPrintlnV2(c.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (c RGBColor) Sprint(a ...any) string {
|
||||
return RenderCode(c.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (c RGBColor) Sprintf(format string, a ...any) 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])
|
||||
}
|
||||
|
||||
// RgbString to color code string without prefix. eg: "204,123,56"
|
||||
func (c RGBColor) RgbString() string {
|
||||
return fmt.Sprintf("%d,%d,%d", 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 ""
|
||||
}
|
||||
|
||||
// ToBg convert to background color
|
||||
func (c RGBColor) ToBg() RGBColor {
|
||||
c[3] = AsBg
|
||||
return c
|
||||
}
|
||||
|
||||
// ToFg convert to foreground color
|
||||
func (c RGBColor) ToFg() RGBColor {
|
||||
c[3] = AsFg
|
||||
return c
|
||||
}
|
||||
|
||||
// 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 supports set foreground and 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 ...any) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and print message
|
||||
func (s *RGBStyle) Printf(format string, a ...any) {
|
||||
doPrintV2(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println print message with newline
|
||||
func (s *RGBStyle) Println(a ...any) {
|
||||
doPrintlnV2(s.String(), a)
|
||||
}
|
||||
|
||||
// Sprint returns rendered message
|
||||
func (s *RGBStyle) Sprint(a ...any) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendered message
|
||||
func (s *RGBStyle) Sprintf(format string, a ...any) 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
|
||||
}
|
||||
567
vendor/github.com/gookit/color/color_tag.go
generated
vendored
567
vendor/github.com/gookit/color/color_tag.go
generated
vendored
@@ -1,567 +0,0 @@
|
||||
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 fg 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
|
||||
"magenta1": "1;35",
|
||||
"mgb": "1;35",
|
||||
"mga1": "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",
|
||||
"lightMagenta1": "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",
|
||||
"italic": "3",
|
||||
"i": "3", // italic
|
||||
"underscore": "4",
|
||||
"us": "4", // short name for 'underscore'
|
||||
"blink": "5",
|
||||
"fb": "6", // fast blink
|
||||
"reverse": "7",
|
||||
"st": "9", // strikethrough
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* internal defined tag attributes
|
||||
*************************************************************/
|
||||
|
||||
// built-in attributes for fg,bg 16-colors and op codes.
|
||||
var (
|
||||
attrFgs = map[string]string{
|
||||
// basic colors
|
||||
|
||||
"black": FgBlack.Code(),
|
||||
"red": "31",
|
||||
"green": "32",
|
||||
"brown": "33", // #A52A2A
|
||||
"yellow": "33",
|
||||
"ylw": "33",
|
||||
"blue": "34",
|
||||
"cyan": "36",
|
||||
"magenta": "35",
|
||||
"mga": "35",
|
||||
"white": FgWhite.Code(),
|
||||
"default": "39", // no color
|
||||
"normal": "39", // no color
|
||||
|
||||
// light/hi colors
|
||||
|
||||
"darkGray": FgDarkGray.Code(),
|
||||
"dark_gray": "90",
|
||||
"gray": "90",
|
||||
"lightYellow": "93",
|
||||
"light_yellow": "93",
|
||||
"hiYellow": "93",
|
||||
"hi_yellow": "93",
|
||||
"lightMagenta": "95",
|
||||
"light_magenta": "95",
|
||||
"hiMagenta": "95",
|
||||
"hi_magenta": "95",
|
||||
"hi_mga": "95",
|
||||
"lightRed": "91",
|
||||
"light_red": "91",
|
||||
"hiRed": "91",
|
||||
"hi_red": "91",
|
||||
"lightGreen": "92",
|
||||
"light_green": "92",
|
||||
"hiGreen": "92",
|
||||
"hi_green": "92",
|
||||
"lightBlue": "94",
|
||||
"light_blue": "94",
|
||||
"hiBlue": "94",
|
||||
"hi_blue": "94",
|
||||
"lightCyan": "96",
|
||||
"light_cyan": "96",
|
||||
"hiCyan": "96",
|
||||
"hi_cyan": "96",
|
||||
"lightWhite": "97",
|
||||
"light_white": "97",
|
||||
}
|
||||
|
||||
attrBgs = map[string]string{
|
||||
// basic colors
|
||||
|
||||
"black": BgBlack.Code(),
|
||||
"red": "41",
|
||||
"green": "42",
|
||||
"brown": "43", // #A52A2A
|
||||
"yellow": "43",
|
||||
"ylw": "43",
|
||||
"blue": "44",
|
||||
"cyan": "46",
|
||||
"magenta": "45",
|
||||
"mga": "45",
|
||||
"white": FgWhite.Code(),
|
||||
"default": "49", // no color
|
||||
"normal": "49", // no color
|
||||
|
||||
// light/hi colors
|
||||
|
||||
"darkGray": BgDarkGray.Code(),
|
||||
"dark_gray": "100",
|
||||
"gray": "100",
|
||||
"lightYellow": "103",
|
||||
"light_yellow": "103",
|
||||
"hiYellow": "103",
|
||||
"hi_yellow": "103",
|
||||
"lightMagenta": "105",
|
||||
"light_magenta": "105",
|
||||
"hiMagenta": "105",
|
||||
"hi_magenta": "105",
|
||||
"hi_mga": "105",
|
||||
"lightRed": "101",
|
||||
"light_red": "101",
|
||||
"hiRed": "101",
|
||||
"hi_red": "101",
|
||||
"lightGreen": "102",
|
||||
"light_green": "102",
|
||||
"hiGreen": "102",
|
||||
"hi_green": "102",
|
||||
"lightBlue": "104",
|
||||
"light_blue": "104",
|
||||
"hiBlue": "104",
|
||||
"hi_blue": "104",
|
||||
"lightCyan": "106",
|
||||
"light_cyan": "106",
|
||||
"hiCyan": "106",
|
||||
"hi_cyan": "106",
|
||||
"lightWhite": BgLightWhite.Code(),
|
||||
"light_white": "107",
|
||||
}
|
||||
|
||||
attrOpts = map[string]string{
|
||||
"reset": OpReset.Code(),
|
||||
"bold": OpBold.Code(),
|
||||
"b": OpBold.Code(),
|
||||
"fuzzy": OpFuzzy.Code(),
|
||||
"italic": OpItalic.Code(),
|
||||
"i": OpItalic.Code(),
|
||||
"underscore": OpUnderscore.Code(),
|
||||
"us": OpUnderscore.Code(),
|
||||
"u": OpUnderscore.Code(),
|
||||
"blink": OpBlink.Code(),
|
||||
"fastblink": OpFastBlink.Code(),
|
||||
"fb": OpFastBlink.Code(),
|
||||
"reverse": OpReverse.Code(),
|
||||
"concealed": OpConcealed.Code(),
|
||||
"strikethrough": OpStrikethrough.Code(),
|
||||
"st": OpStrikethrough.Code(),
|
||||
}
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* parse color tags
|
||||
*************************************************************/
|
||||
|
||||
var (
|
||||
tagParser = TagParser{}
|
||||
// regex for match color 256 code
|
||||
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 given string, replace color tag and return rendered string
|
||||
//
|
||||
// Use built in tags:
|
||||
//
|
||||
// <TAG_NAME>CONTENT</>
|
||||
// // e.g: `<info>message</>`
|
||||
//
|
||||
// Custom tag attributes:
|
||||
//
|
||||
// `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>`
|
||||
// // e.g: `<fg=167;bg=232>wel</>`
|
||||
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, body := item[0], item[1], item[2]
|
||||
|
||||
// use defined color tag name: "<info>content</>" -> tag: "info"
|
||||
if !strings.ContainsRune(tag, '=') {
|
||||
if code := colorTags[tag]; len(code) > 0 {
|
||||
str = strings.Replace(str, full, RenderString(code, body), 1)
|
||||
} else if code, ok := namedRgbMap[tag]; ok {
|
||||
code = strings.Replace(code, ",", ";", -1)
|
||||
now := RenderString(FgRGBPfx+code, body)
|
||||
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 {
|
||||
str = strings.Replace(str, full, RenderString(code, body), 1)
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// 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 code, ok := attrFgs[val]; ok { // attr fg
|
||||
codes = append(codes, code)
|
||||
} else if code := rgbHex256toCode(val, false); code != "" {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
case "bg":
|
||||
if code, ok := attrBgs[val]; ok { // attr bg
|
||||
codes = append(codes, code)
|
||||
} 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 code, ok := attrOpts[n]; ok { // attr ops
|
||||
codes = append(codes, code)
|
||||
}
|
||||
}
|
||||
} else if code, ok := attrOpts[val]; ok {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ...any) 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 ...any) {
|
||||
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 ...any) {
|
||||
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 ...any) {
|
||||
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 ...any) string {
|
||||
return RenderCode(GetTagCode(string(tg)), a...)
|
||||
}
|
||||
|
||||
// Sprintf format and render messages
|
||||
func (tg Tag) Sprintf(format string, a ...any) string {
|
||||
tag := string(tg)
|
||||
str := fmt.Sprintf(format, a...)
|
||||
|
||||
return RenderString(GetTagCode(tag), str)
|
||||
}
|
||||
966
vendor/github.com/gookit/color/convert.go
generated
vendored
966
vendor/github.com/gookit/color/convert.go
generated
vendored
@@ -1,966 +0,0 @@
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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}
|
||||
// )
|
||||
|
||||
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
|
||||
// Tip: only keep foreground color, background color need convert to foreground color for convert to RGB
|
||||
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
|
||||
// - don't add bg color, convert to fg color for convert to RGB
|
||||
// 40: "000000", // black
|
||||
// 41: "c51e14", // red
|
||||
// 42: "1dc121", // green
|
||||
// 43: "c7c329", // yellow
|
||||
// 44: "0a2fc4", // blue
|
||||
// 45: "c839c5", // magenta
|
||||
// 46: "20c5c6", // cyan
|
||||
// 47: "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
|
||||
// - don't add bg color
|
||||
// 100: "686868", // lightBlack/darkGray
|
||||
// 101: "fd6f6b", // lightRed
|
||||
// 102: "67f86f", // lightGreen
|
||||
// 103: "fffa72", // lightYellow
|
||||
// 104: "6a76fb", // lightBlue
|
||||
// 105: "fd7cfc", // lightMagenta
|
||||
// 106: "68fdfe", // lightCyan
|
||||
// 107: "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
|
||||
*************************************************************/
|
||||
|
||||
// BasicToHex convert basic color to hex string.
|
||||
func BasicToHex(val uint8) string {
|
||||
val = Bg2Fg(val)
|
||||
return basic2hexMap[val]
|
||||
}
|
||||
|
||||
// Basic2hex convert basic color to hex string.
|
||||
func Basic2hex(val uint8) string {
|
||||
return BasicToHex(val)
|
||||
}
|
||||
|
||||
// Hex2basic convert hex string to basic color code.
|
||||
func Hex2basic(hex string, asBg ...bool) uint8 {
|
||||
val := hex2basicMap[hex]
|
||||
|
||||
if len(asBg) > 0 && asBg[0] {
|
||||
return Fg2Bg(val)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 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 convert RGB-code to 16-code, 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}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* HSL color <=> RGB/True color
|
||||
************************************************************
|
||||
* h,s,l = Hue, Saturation, Lightness
|
||||
*
|
||||
* refers
|
||||
* http://en.wikipedia.org/wiki/HSL_color_space
|
||||
* https://www.w3.org/TR/css-color-3/#hsl-color
|
||||
* https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
|
||||
* https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
|
||||
* https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
|
||||
*
|
||||
* examples:
|
||||
* color: hsl(0, 100%, 50%) // red
|
||||
* color: hsl(120, 100%, 50%) // lime
|
||||
* color: hsl(120, 100%, 25%) // dark green
|
||||
* color: hsl(120, 100%, 75%) // light green
|
||||
* color: hsl(120, 75%, 75%) // pastel green, and so on
|
||||
*/
|
||||
|
||||
// HslIntToRgb Converts an HSL color value to RGB
|
||||
// Assumes h: 0-360, s: 0-100, l: 0-100
|
||||
// returns r, g, and b in the set [0, 255].
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// HslIntToRgb(0, 100, 50) // red
|
||||
// HslIntToRgb(120, 100, 50) // lime
|
||||
// HslIntToRgb(120, 100, 25) // dark green
|
||||
// HslIntToRgb(120, 100, 75) // light green
|
||||
func HslIntToRgb(h, s, l int) (rgb []uint8) {
|
||||
return HslToRgb(float64(h)/360, float64(s)/100, float64(l)/100)
|
||||
}
|
||||
|
||||
// HslToRgb Converts an HSL color value to RGB. Conversion formula
|
||||
// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
// Assumes h, s, and l are contained in the set [0, 1]
|
||||
// returns r, g, and b in the set [0, 255].
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// rgbVals := HslToRgb(0, 1, 0.5) // red
|
||||
func HslToRgb(h, s, l float64) (rgb []uint8) {
|
||||
var r, g, b float64
|
||||
|
||||
if s == 0 { // achromatic
|
||||
r, g, b = l, l, l
|
||||
} else {
|
||||
var hue2rgb = func(p, q, t float64) float64 {
|
||||
if t < 0.0 {
|
||||
t += 1
|
||||
}
|
||||
if t > 1.0 {
|
||||
t -= 1
|
||||
}
|
||||
|
||||
if t < 1.0/6.0 {
|
||||
return p + (q-p)*6.0*t
|
||||
}
|
||||
|
||||
if t < 1.0/2.0 {
|
||||
return q
|
||||
}
|
||||
|
||||
if t < 2.0/3.0 {
|
||||
return p + (q-p)*(2.0/3.0-t)*6.0
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// q = l < 0.5 ? l * (1 + s) : l + s - l*s
|
||||
var q float64
|
||||
if l < 0.5 {
|
||||
q = l * (1.0 + s)
|
||||
} else {
|
||||
q = l + s - l*s
|
||||
}
|
||||
|
||||
var p = 2.0*l - q
|
||||
|
||||
r = hue2rgb(p, q, h+1.0/3.0)
|
||||
g = hue2rgb(p, q, h)
|
||||
b = hue2rgb(p, q, h-1.0/3.0)
|
||||
}
|
||||
|
||||
// return []uint8{uint8(r * 255), uint8(g * 255), uint8(b * 255)}
|
||||
return []uint8{
|
||||
uint8(math.Round(r * 255)),
|
||||
uint8(math.Round(g * 255)),
|
||||
uint8(math.Round(b * 255)),
|
||||
}
|
||||
}
|
||||
|
||||
// RgbToHslInt Converts an RGB color value to HSL. Conversion formula
|
||||
// Assumes r, g, and b are contained in the set [0, 255] and
|
||||
// returns [h,s,l] h: 0-360, s: 0-100, l: 0-100.
|
||||
func RgbToHslInt(r, g, b uint8) []int {
|
||||
f64s := RgbToHsl(r, g, b)
|
||||
|
||||
return []int{int(f64s[0] * 360), int(f64s[1] * 100), int(f64s[2] * 100)}
|
||||
}
|
||||
|
||||
// RgbToHsl Converts an RGB color value to HSL. Conversion formula
|
||||
//
|
||||
// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
//
|
||||
// Assumes r, g, and b are contained in the set [0, 255] and
|
||||
// returns h, s, and l in the set [0, 1].
|
||||
func RgbToHsl(r, g, b uint8) []float64 {
|
||||
// to float64
|
||||
fr, fg, fb := float64(r), float64(g), float64(b)
|
||||
// percentage
|
||||
pr, pg, pb := float64(r)/255.0, float64(g)/255.0, float64(b)/255.0
|
||||
|
||||
ps := []float64{pr, pg, pb}
|
||||
sort.Float64s(ps)
|
||||
|
||||
min, max := ps[0], ps[2]
|
||||
// max := math.Max(math.Max(pr, pg), pb)
|
||||
// min := math.Min(math.Min(pr, pg), pb)
|
||||
mid := (max + min) / 2
|
||||
|
||||
h, s, l := mid, mid, mid
|
||||
if max == min {
|
||||
h, s = 0, 0 // achromatic
|
||||
} else {
|
||||
var d = max - min
|
||||
// s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
||||
s = compareF64Val(l > 0.5, d/(2-max-min), d/(max+min))
|
||||
|
||||
switch max {
|
||||
case fr:
|
||||
// h = (g - b) / d + (g < b ? 6 : 0)
|
||||
h = (fg - fb) / d
|
||||
h += compareF64Val(g < b, 6, 0)
|
||||
case fg:
|
||||
h = (fb-fr)/d + 2
|
||||
case fb:
|
||||
h = (fr-fg)/d + 4
|
||||
}
|
||||
|
||||
h /= 6
|
||||
}
|
||||
|
||||
return []float64{h, s, l}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* HSV color <=> RGB/True color
|
||||
************************************************************
|
||||
* h,s,l = Hue, Saturation, Value(Brightness)
|
||||
*
|
||||
* refers
|
||||
* https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
|
||||
* https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
|
||||
* https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
|
||||
*/
|
||||
|
||||
// HsvToRgb Converts an HSL color value to RGB. Conversion formula
|
||||
// adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
|
||||
// Assumes h: 0-360, s: 0-100, l: 0-100
|
||||
// returns r, g, and b in the set [0, 255].
|
||||
func HsvToRgb(h, s, v int) (rgb []uint8) {
|
||||
// TODO ...
|
||||
return
|
||||
}
|
||||
|
||||
// Named rgb colors
|
||||
// https://www.w3.org/TR/css-color-3/#svg-color
|
||||
var namedRgbMap = map[string]string{
|
||||
"aliceblue": "240,248,255", // #F0F8FF
|
||||
"antiquewhite": "250,235,215", // #FAEBD7
|
||||
"aqua": "0,255,255", // #00FFFF
|
||||
"aquamarine": "127,255,212", // #7FFFD4
|
||||
"azure": "240,255,255", // #F0FFFF
|
||||
"beige": "245,245,220", // #F5F5DC
|
||||
"bisque": "255,228,196", // #FFE4C4
|
||||
"black": "0,0,0", // #000000
|
||||
"blanchedalmond": "255,235,205", // #FFEBCD
|
||||
"blue": "0,0,255", // #0000FF
|
||||
"blueviolet": "138,43,226", // #8A2BE2
|
||||
"brown": "165,42,42", // #A52A2A
|
||||
"burlywood": "222,184,135", // #DEB887
|
||||
"cadetblue": "95,158,160", // #5F9EA0
|
||||
"chartreuse": "127,255,0", // #7FFF00
|
||||
"chocolate": "210,105,30", // #D2691E
|
||||
"coral": "255,127,80", // #FF7F50
|
||||
"cornflowerblue": "100,149,237", // #6495ED
|
||||
"cornsilk": "255,248,220", // #FFF8DC
|
||||
"crimson": "220,20,60", // #DC143C
|
||||
"cyan": "0,255,255", // #00FFFF
|
||||
"darkblue": "0,0,139", // #00008B
|
||||
"darkcyan": "0,139,139", // #008B8B
|
||||
"darkgoldenrod": "184,134,11", // #B8860B
|
||||
"darkgray": "169,169,169", // #A9A9A9
|
||||
"darkgreen": "0,100,0", // #006400
|
||||
"darkgrey": "169,169,169", // #A9A9A9
|
||||
"darkkhaki": "189,183,107", // #BDB76B
|
||||
"darkmagenta": "139,0,139", // #8B008B
|
||||
"darkolivegreen": "85,107,47", // #556B2F
|
||||
"darkorange": "255,140,0", // #FF8C00
|
||||
"darkorchid": "153,50,204", // #9932CC
|
||||
"darkred": "139,0,0", // #8B0000
|
||||
"darksalmon": "233,150,122", // #E9967A
|
||||
"darkseagreen": "143,188,143", // #8FBC8F
|
||||
"darkslateblue": "72,61,139", // #483D8B
|
||||
"darkslategray": "47,79,79", // #2F4F4F
|
||||
"darkslategrey": "47,79,79", // #2F4F4F
|
||||
"darkturquoise": "0,206,209", // #00CED1
|
||||
"darkviolet": "148,0,211", // #9400D3
|
||||
"deeppink": "255,20,147", // #FF1493
|
||||
"deepskyblue": "0,191,255", // #00BFFF
|
||||
"dimgray": "105,105,105", // #696969
|
||||
"dimgrey": "105,105,105", // #696969
|
||||
"dodgerblue": "30,144,255", // #1E90FF
|
||||
"firebrick": "178,34,34", // #B22222
|
||||
"floralwhite": "255,250,240", // #FFFAF0
|
||||
"forestgreen": "34,139,34", // #228B22
|
||||
"fuchsia": "255,0,255", // #FF00FF
|
||||
"gainsboro": "220,220,220", // #DCDCDC
|
||||
"ghostwhite": "248,248,255", // #F8F8FF
|
||||
"gold": "255,215,0", // #FFD700
|
||||
"goldenrod": "218,165,32", // #DAA520
|
||||
"gray": "128,128,128", // #808080
|
||||
"green": "0,128,0", // #008000
|
||||
"greenyellow": "173,255,47", // #ADFF2F
|
||||
"grey": "128,128,128", // #808080
|
||||
"honeydew": "240,255,240", // #F0FFF0
|
||||
"hotpink": "255,105,180", // #FF69B4
|
||||
"indianred": "205,92,92", // #CD5C5C
|
||||
"indigo": "75,0,130", // #4B0082
|
||||
"ivory": "255,255,240", // #FFFFF0
|
||||
"khaki": "240,230,140", // #F0E68C
|
||||
"lavender": "230,230,250", // #E6E6FA
|
||||
"lavenderblush": "255,240,245", // #FFF0F5
|
||||
"lawngreen": "124,252,0", // #7CFC00
|
||||
"lemonchiffon": "255,250,205", // #FFFACD
|
||||
"lightblue": "173,216,230", // #ADD8E6
|
||||
"lightcoral": "240,128,128", // #F08080
|
||||
"lightcyan": "224,255,255", // #E0FFFF
|
||||
"lightgoldenrodyellow": "250,250,210", // #FAFAD2
|
||||
"lightgray": "211,211,211", // #D3D3D3
|
||||
"lightgreen": "144,238,144", // #90EE90
|
||||
"lightgrey": "211,211,211", // #D3D3D3
|
||||
"lightpink": "255,182,193", // #FFB6C1
|
||||
"lightsalmon": "255,160,122", // #FFA07A
|
||||
"lightseagreen": "32,178,170", // #20B2AA
|
||||
"lightskyblue": "135,206,250", // #87CEFA
|
||||
"lightslategray": "119,136,153", // #778899
|
||||
"lightslategrey": "119,136,153", // #778899
|
||||
"lightsteelblue": "176,196,222", // #B0C4DE
|
||||
"lightyellow": "255,255,224", // #FFFFE0
|
||||
"lime": "0,255,0", // #00FF00
|
||||
"limegreen": "50,205,50", // #32CD32
|
||||
"linen": "250,240,230", // #FAF0E6
|
||||
"magenta": "255,0,255", // #FF00FF
|
||||
"maroon": "128,0,0", // #800000
|
||||
"mediumaquamarine": "102,205,170", // #66CDAA
|
||||
"mediumblue": "0,0,205", // #0000CD
|
||||
"mediumorchid": "186,85,211", // #BA55D3
|
||||
"mediumpurple": "147,112,219", // #9370DB
|
||||
"mediumseagreen": "60,179,113", // #3CB371
|
||||
"mediumslateblue": "123,104,238", // #7B68EE
|
||||
"mediumspringgreen": "0,250,154", // #00FA9A
|
||||
"mediumturquoise": "72,209,204", // #48D1CC
|
||||
"mediumvioletred": "199,21,133", // #C71585
|
||||
"midnightblue": "25,25,112", // #191970
|
||||
"mintcream": "245,255,250", // #F5FFFA
|
||||
"mistyrose": "255,228,225", // #FFE4E1
|
||||
"moccasin": "255,228,181", // #FFE4B5
|
||||
"navajowhite": "255,222,173", // #FFDEAD
|
||||
"navy": "0,0,128", // #000080
|
||||
"oldlace": "253,245,230", // #FDF5E6
|
||||
"olive": "128,128,0", // #808000
|
||||
"olivedrab": "107,142,35", // #6B8E23
|
||||
"orange": "255,165,0", // #FFA500
|
||||
"orangered": "255,69,0", // #FF4500
|
||||
"orchid": "218,112,214", // #DA70D6
|
||||
"palegoldenrod": "238,232,170", // #EEE8AA
|
||||
"palegreen": "152,251,152", // #98FB98
|
||||
"paleturquoise": "175,238,238", // #AFEEEE
|
||||
"palevioletred": "219,112,147", // #DB7093
|
||||
"papayawhip": "255,239,213", // #FFEFD5
|
||||
"peachpuff": "255,218,185", // #FFDAB9
|
||||
"peru": "205,133,63", // #CD853F
|
||||
"pink": "255,192,203", // #FFC0CB
|
||||
"plum": "221,160,221", // #DDA0DD
|
||||
"powderblue": "176,224,230", // #B0E0E6
|
||||
"purple": "128,0,128", // #800080
|
||||
"red": "255,0,0", // #FF0000
|
||||
"rosybrown": "188,143,143", // #BC8F8F
|
||||
"royalblue": "65,105,225", // #4169E1
|
||||
"saddlebrown": "139,69,19", // #8B4513
|
||||
"salmon": "250,128,114", // #FA8072
|
||||
"sandybrown": "244,164,96", // #F4A460
|
||||
"seagreen": "46,139,87", // #2E8B57
|
||||
"seashell": "255,245,238", // #FFF5EE
|
||||
"sienna": "160,82,45", // #A0522D
|
||||
"silver": "192,192,192", // #C0C0C0
|
||||
"skyblue": "135,206,235", // #87CEEB
|
||||
"slateblue": "106,90,205", // #6A5ACD
|
||||
"slategray": "112,128,144", // #708090
|
||||
"slategrey": "112,128,144", // #708090
|
||||
"snow": "255,250,250", // #FFFAFA
|
||||
"springgreen": "0,255,127", // #00FF7F
|
||||
"steelblue": "70,130,180", // #4682B4
|
||||
"tan": "210,180,140", // #D2B48C
|
||||
"teal": "0,128,128", // #008080
|
||||
"thistle": "216,191,216", // #D8BFD8
|
||||
"tomato": "255,99,71", // #FF6347
|
||||
"turquoise": "64,224,208", // #40E0D0
|
||||
"violet": "238,130,238", // #EE82EE
|
||||
"wheat": "245,222,179", // #F5DEB3
|
||||
"white": "255,255,255", // #FFFFFF
|
||||
"whitesmoke": "245,245,245", // #F5F5F5
|
||||
"yellow": "255,255,0", // #FFFF00
|
||||
"yellowgreen": "154,205,50", // #9ACD32
|
||||
}
|
||||
291
vendor/github.com/gookit/color/detect_env.go
generated
vendored
291
vendor/github.com/gookit/color/detect_env.go
generated
vendored
@@ -1,291 +0,0 @@
|
||||
package color
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
// Level is the color level supported by a terminal.
|
||||
type Level = terminfo.ColorLevel
|
||||
|
||||
// terminal color available level alias of the terminfo.ColorLevel*
|
||||
const (
|
||||
LevelNo = terminfo.ColorLevelNone // not support color.
|
||||
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
|
||||
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
|
||||
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* helper methods for detect color supports
|
||||
*************************************************************/
|
||||
|
||||
// DetectColorLevel for current env
|
||||
//
|
||||
// NOTICE: The method will detect terminal info each times,
|
||||
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
|
||||
func DetectColorLevel() Level {
|
||||
level, _ := detectTermColorLevel()
|
||||
return level
|
||||
}
|
||||
|
||||
// detect terminal color support level
|
||||
//
|
||||
// refer https://github.com/Delta456/box-cli-maker
|
||||
func detectTermColorLevel() (level Level, 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) Level {
|
||||
// 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 {
|
||||
detectedWSL = true
|
||||
|
||||
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)
|
||||
return strings.Contains(wslContents, "Microsoft")
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
// 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 supports 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"
|
||||
return len(os.Getenv("MSYSTEM")) > 0
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// IsSupport16Color 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 to 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
|
||||
}
|
||||
49
vendor/github.com/gookit/color/detect_nonwin.go
generated
vendored
49
vendor/github.com/gookit/color/detect_nonwin.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
//go:build !windows
|
||||
// +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) (Level, 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)
|
||||
}
|
||||
250
vendor/github.com/gookit/color/detect_windows.go
generated
vendored
250
vendor/github.com/gookit/color/detect_windows.go
generated
vendored
@@ -1,250 +0,0 @@
|
||||
//go:build windows
|
||||
// +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 Level, 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
|
||||
}
|
||||
25
vendor/github.com/gookit/color/index.html
generated
vendored
25
vendor/github.com/gookit/color/index.html
generated
vendored
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css">
|
||||
<title>Color - A command-line color library with true color support, universal API methods and Windows support.</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
repo: 'gookit/color',
|
||||
maxLevel: 3,
|
||||
// 加载 _navbar.md
|
||||
// loadNavbar: true,
|
||||
loadNavbar: '_examples/navbar.md',
|
||||
// 加载 _sidebar.md
|
||||
// loadSidebar: true,
|
||||
}
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
133
vendor/github.com/gookit/color/printer.go
generated
vendored
133
vendor/github.com/gookit/color/printer.go
generated
vendored
@@ -1,133 +0,0 @@
|
||||
package color
|
||||
|
||||
import "fmt"
|
||||
|
||||
/*************************************************************
|
||||
* colored message Printer
|
||||
*************************************************************/
|
||||
|
||||
// PrinterFace interface
|
||||
type PrinterFace interface {
|
||||
fmt.Stringer
|
||||
Sprint(a ...any) string
|
||||
Sprintf(format string, a ...any) string
|
||||
Print(a ...any)
|
||||
Printf(format string, a ...any)
|
||||
Println(a ...any)
|
||||
}
|
||||
|
||||
// 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 ...any) string {
|
||||
return RenderCode(p.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf returns format and rendering colored messages
|
||||
func (p *Printer) Sprintf(format string, a ...any) string {
|
||||
return RenderString(p.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Print rendering colored messages
|
||||
func (p *Printer) Print(a ...any) {
|
||||
doPrintV2(p.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf format and rendering colored messages
|
||||
func (p *Printer) Printf(format string, a ...any) {
|
||||
doPrintV2(p.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println rendering colored messages with newline
|
||||
func (p *Printer) Println(a ...any) {
|
||||
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 ...any) {
|
||||
Print(v...)
|
||||
}
|
||||
|
||||
// Printf message
|
||||
func (s *SimplePrinter) Printf(format string, v ...any) {
|
||||
Printf(format, v...)
|
||||
}
|
||||
|
||||
// Println message
|
||||
func (s *SimplePrinter) Println(v ...any) {
|
||||
Println(v...)
|
||||
}
|
||||
|
||||
// Successf message
|
||||
func (s *SimplePrinter) Successf(format string, a ...any) {
|
||||
Success.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Successln message
|
||||
func (s *SimplePrinter) Successln(a ...any) {
|
||||
Success.Println(a...)
|
||||
}
|
||||
|
||||
// Infof message
|
||||
func (s *SimplePrinter) Infof(format string, a ...any) {
|
||||
Info.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Infoln message
|
||||
func (s *SimplePrinter) Infoln(a ...any) {
|
||||
Info.Println(a...)
|
||||
}
|
||||
|
||||
// Warnf message
|
||||
func (s *SimplePrinter) Warnf(format string, a ...any) {
|
||||
Warn.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Warnln message
|
||||
func (s *SimplePrinter) Warnln(a ...any) {
|
||||
Warn.Println(a...)
|
||||
}
|
||||
|
||||
// Errorf message
|
||||
func (s *SimplePrinter) Errorf(format string, a ...any) {
|
||||
Error.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Errorln message
|
||||
func (s *SimplePrinter) Errorln(a ...any) {
|
||||
Error.Println(a...)
|
||||
}
|
||||
324
vendor/github.com/gookit/color/style.go
generated
vendored
324
vendor/github.com/gookit/color/style.go
generated
vendored
@@ -1,324 +0,0 @@
|
||||
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 colored text
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// color.New(color.FgGreen).Render("text")
|
||||
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
|
||||
func (s Style) Render(a ...any) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Renderln render text with newline.
|
||||
// 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 ...any) string {
|
||||
return RenderWithSpaces(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprint is alias of the 'Render'
|
||||
func (s Style) Sprint(a ...any) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Sprintf format and render message.
|
||||
func (s Style) Sprintf(format string, a ...any) string {
|
||||
return RenderString(s.String(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Print render and Print text
|
||||
func (s Style) Print(a ...any) {
|
||||
doPrintV2(s.String(), fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Printf render and print text
|
||||
func (s Style) Printf(format string, a ...any) {
|
||||
doPrintV2(s.Code(), fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Println render and print text line
|
||||
func (s Style) Println(a ...any) {
|
||||
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 ...any) {
|
||||
// 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 ...any) {
|
||||
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 ...any) {
|
||||
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 ...any) {
|
||||
s.Styles["info"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Infoln message print
|
||||
func (s *Scheme) Infoln(v ...any) {
|
||||
s.Styles["info"].Println(v...)
|
||||
}
|
||||
|
||||
// Warnf message print
|
||||
func (s *Scheme) Warnf(format string, a ...any) {
|
||||
s.Styles["warn"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Warnln message print
|
||||
func (s *Scheme) Warnln(v ...any) {
|
||||
s.Styles["warn"].Println(v...)
|
||||
}
|
||||
|
||||
// Errorf message print
|
||||
func (s *Scheme) Errorf(format string, a ...any) {
|
||||
s.Styles["error"].Printf(format, a...)
|
||||
}
|
||||
|
||||
// Errorln message print
|
||||
func (s *Scheme) Errorln(v ...any) {
|
||||
s.Styles["error"].Println(v...)
|
||||
}
|
||||
209
vendor/github.com/gookit/color/utils.go
generated
vendored
209
vendor/github.com/gookit/color/utils.go
generated
vendored
@@ -1,209 +0,0 @@
|
||||
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 ...any) {
|
||||
Fprint(output, a...)
|
||||
}
|
||||
|
||||
// Printf format and print messages
|
||||
func Printf(format string, a ...any) {
|
||||
Fprintf(output, format, a...)
|
||||
}
|
||||
|
||||
// Println messages with new line
|
||||
func Println(a ...any) {
|
||||
Fprintln(output, a...)
|
||||
}
|
||||
|
||||
// Fprint print rendered messages to writer
|
||||
//
|
||||
// Notice: will ignore print error
|
||||
func Fprint(w io.Writer, a ...any) {
|
||||
_, err := fmt.Fprint(w, Render(a...))
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
// Fprintf print format and rendered messages to writer.
|
||||
// Notice: will ignore print error
|
||||
func Fprintf(w io.Writer, format string, a ...any) {
|
||||
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 ...any) {
|
||||
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 ...any) {
|
||||
l.Print(Render(a...))
|
||||
}
|
||||
|
||||
// Render parse color tags, return rendered string.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// text := Render("<info>hello</> <cyan>world</>!")
|
||||
// fmt.Println(text)
|
||||
func Render(a ...any) string {
|
||||
if len(a) == 0 {
|
||||
return ""
|
||||
}
|
||||
return ReplaceTag(fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Sprint parse color tags, return rendered string
|
||||
func Sprint(a ...any) string {
|
||||
if len(a) == 0 {
|
||||
return ""
|
||||
}
|
||||
return ReplaceTag(fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Sprintf format and return rendered string
|
||||
func Sprintf(format string, a ...any) 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) }
|
||||
|
||||
// Uint8sToInts convert []uint8 to []int
|
||||
// func Uint8sToInts(u8s []uint8 ) []int {
|
||||
// ints := make([]int, len(u8s))
|
||||
// for i, u8 := range u8s {
|
||||
// ints[i] = int(u8)
|
||||
// }
|
||||
// return ints
|
||||
// }
|
||||
|
||||
/*************************************************************
|
||||
* 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)
|
||||
}
|
||||
|
||||
// new implementation, support render full color code on pwsh.exe, cmd.exe
|
||||
func doPrintlnV2(code string, args []any) {
|
||||
str := formatArgsForPrintln(args)
|
||||
_, err := fmt.Fprintln(output, RenderString(code, str))
|
||||
saveInternalError(err)
|
||||
}
|
||||
|
||||
// use Println, will add spaces for each arg
|
||||
func formatArgsForPrintln(args []any) (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 ...any) {
|
||||
if debugMode {
|
||||
fmt.Print("COLOR_DEBUG: ")
|
||||
fmt.Printf(f, v...)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// equals: return ok ? val1 : val2
|
||||
func isValidUint8(val int) bool {
|
||||
return val >= 0 && val < 256
|
||||
}
|
||||
|
||||
// equals: return ok ? val1 : val2
|
||||
func compareVal(ok bool, val1, val2 uint8) uint8 {
|
||||
if ok {
|
||||
return val1
|
||||
}
|
||||
return val2
|
||||
}
|
||||
|
||||
// equals: return ok ? val1 : val2
|
||||
func compareF64Val(ok bool, val1, val2 float64) float64 {
|
||||
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
|
||||
}
|
||||
5
vendor/github.com/gookit/config/v2/README.md
generated
vendored
5
vendor/github.com/gookit/config/v2/README.md
generated
vendored
@@ -421,7 +421,10 @@ config.WithOptions(func(opt *Options) {
|
||||
|
||||
### Options: Parse default
|
||||
|
||||
Support parse default value by struct tag `default`
|
||||
Support parse default value by struct tag `default`, and support parse fields in sub struct.
|
||||
|
||||
> **NOTE**⚠️ If you want to parse a sub-struct, you need to set the `default:""` flag on the parent struct,
|
||||
> otherwise the fields of the sub-struct will not be resolved.
|
||||
|
||||
```go
|
||||
// add option: config.ParseDefault
|
||||
|
||||
6
vendor/github.com/gookit/config/v2/README.zh-CN.md
generated
vendored
6
vendor/github.com/gookit/config/v2/README.zh-CN.md
generated
vendored
@@ -26,7 +26,7 @@
|
||||
- `Readonly` 支持设置配置数据只读
|
||||
- `EnableCache` 支持设置配置数据缓存
|
||||
- `ParseEnv` 支持获取时自动解析string值里的ENV变量(`shell: ${SHELL}` -> `shell: /bin/zsh`)
|
||||
- `ParseDefault` 支持在绑定数据到结构体时解析默认值 (tag: `default:"def_value"`, 配合ParseEnv也支持ENV变量)
|
||||
- `ParseDefault` 支持在绑定数据到结构体时解析默认值 (tag: `default:"def_value"`, 配合`ParseEnv`也支持ENV变量)
|
||||
- `ParseTime` 支持绑定数据到struct时自动转换 `10s`,`2m` 为 `time.Duration`
|
||||
- 完整选项设置请查看 `config.Options`
|
||||
- 支持将全部或部分配置数据绑定到结构体 `config.BindStruct("key", &s)`
|
||||
@@ -414,7 +414,9 @@ config.WithOptions(func(opt *Options) {
|
||||
|
||||
### 选项: 解析默认值
|
||||
|
||||
NEW: 支持通过结构标签 `default` 解析并设置默认值
|
||||
NEW: 支持通过结构标签 `default` 解析并设置默认值,支持嵌套解析处理。
|
||||
|
||||
> 注意 ⚠️ 如果想要解析子结构体字段,需要对父结构体设置 `default:""` 标记,否则不会解析子结构体的字段。
|
||||
|
||||
```go
|
||||
// add option: config.ParseDefault
|
||||
|
||||
13
vendor/github.com/gookit/config/v2/export.go
generated
vendored
13
vendor/github.com/gookit/config/v2/export.go
generated
vendored
@@ -7,8 +7,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/gookit/goutil/structs"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// Decode all config data to the dst ptr
|
||||
@@ -37,17 +37,13 @@ func (c *Config) Decode(dst any) error {
|
||||
func MapStruct(key string, dst any) error { return dc.MapStruct(key, dst) }
|
||||
|
||||
// MapStruct alias method of the 'Structure'
|
||||
func (c *Config) MapStruct(key string, dst any) error {
|
||||
return c.Structure(key, dst)
|
||||
}
|
||||
func (c *Config) MapStruct(key string, dst any) error { return c.Structure(key, dst) }
|
||||
|
||||
// BindStruct alias method of the 'Structure'
|
||||
func BindStruct(key string, dst any) error { return dc.BindStruct(key, dst) }
|
||||
|
||||
// BindStruct alias method of the 'Structure'
|
||||
func (c *Config) BindStruct(key string, dst any) error {
|
||||
return c.Structure(key, dst)
|
||||
}
|
||||
func (c *Config) BindStruct(key string, dst any) error { return c.Structure(key, dst) }
|
||||
|
||||
// MapOnExists mapping data to the dst structure only on key exists.
|
||||
func MapOnExists(key string, dst any) error {
|
||||
@@ -63,7 +59,6 @@ func (c *Config) MapOnExists(key string, dst any) error {
|
||||
if err != nil && err == ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -86,6 +81,7 @@ func (c *Config) Structure(key string, dst any) (err error) {
|
||||
if c.opts.ParseDefault {
|
||||
err = structs.InitDefaults(dst, func(opt *structs.InitOptions) {
|
||||
opt.ParseEnv = c.opts.ParseEnv
|
||||
opt.ParseTime = c.opts.ParseTime // add ParseTime support on parse default value
|
||||
})
|
||||
}
|
||||
return
|
||||
@@ -116,6 +112,7 @@ func (c *Config) Structure(key string, dst any) (err error) {
|
||||
if c.opts.ParseDefault {
|
||||
err = structs.InitDefaults(dst, func(opt *structs.InitOptions) {
|
||||
opt.ParseEnv = c.opts.ParseEnv
|
||||
opt.ParseTime = c.opts.ParseTime
|
||||
})
|
||||
}
|
||||
return err
|
||||
|
||||
7
vendor/github.com/gookit/config/v2/options.go
generated
vendored
7
vendor/github.com/gookit/config/v2/options.go
generated
vendored
@@ -4,8 +4,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/gookit/goutil"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// there are some event names for config data changed.
|
||||
@@ -33,12 +33,15 @@ type Options struct {
|
||||
// ParseDefault tag on binding data to struct. default: false
|
||||
//
|
||||
// - tag: default
|
||||
//
|
||||
// NOTE: If you want to parse a substruct, you need to set the `default:""` flag on the struct,
|
||||
// otherwise the fields that will not resolve to it will not be resolved.
|
||||
ParseDefault bool
|
||||
// Readonly config is readonly. default: false
|
||||
Readonly bool
|
||||
// EnableCache enable config data cache. default: false
|
||||
EnableCache bool
|
||||
// ParseKey support key path, allow find value by key path. default: true
|
||||
// ParseKey support key path, allow finding value by key path. default: true
|
||||
//
|
||||
// - eg: 'key.sub' will find `map[key]sub`
|
||||
ParseKey bool
|
||||
|
||||
16
vendor/github.com/gookit/config/v2/util.go
generated
vendored
16
vendor/github.com/gookit/config/v2/util.go
generated
vendored
@@ -4,10 +4,10 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/gookit/goutil/envutil"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
)
|
||||
|
||||
// ValDecodeHookFunc returns a mapstructure.DecodeHookFunc
|
||||
@@ -31,15 +31,9 @@ func ValDecodeHookFunc(parseEnv, parseTime bool) mapstructure.DecodeHookFunc {
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// start char is number(1-9)
|
||||
if str[0] > '0' && str[0] <= '9' {
|
||||
// parse time string. eg: 10s
|
||||
if parseTime && t.Kind() == reflect.Int64 {
|
||||
dur, err := time.ParseDuration(str)
|
||||
if err == nil {
|
||||
return dur, nil
|
||||
}
|
||||
}
|
||||
// feat: support parse time or duration string. eg: 10s
|
||||
if parseTime && str[0] > '0' && str[0] <= '9' {
|
||||
return reflects.ToTimeOrDuration(str, t)
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
337
vendor/github.com/gookit/goutil/README.md
generated
vendored
337
vendor/github.com/gookit/goutil/README.md
generated
vendored
@@ -7,56 +7,63 @@
|
||||
[](https://coveralls.io/github/gookit/goutil?branch=master)
|
||||
[](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
💪 Useful utils(**700+**) package for the Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem, system, testing and more.
|
||||
💪 Useful utils(**800+**) package for the Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem, system, testing and more.
|
||||
|
||||
> **[中文说明](README.zh-CN.md)**
|
||||
|
||||
**Basic packages:**
|
||||
## Packages
|
||||
|
||||
### Basic packages
|
||||
|
||||
- [`arrutil`](arrutil): Array/Slice util functions. eg: check, convert, formatting, enum, collections
|
||||
- [`cliutil`](cliutil) Command-line util functions. eg: colored print, read input, exec command
|
||||
- [`envutil`](envutil) ENV util for current runtime env information. eg: get one, get info, parse var
|
||||
- [`fmtutil`](fmtutil) Format data util functions. eg: data, size, time
|
||||
- [`fsutil`](fsutil) Filesystem util functions, quick create, read and write file. eg: file and dir check, operate
|
||||
- [`goinfo`](goinfo) provide some standard util functions for go.
|
||||
- [`jsonutil`](jsonutil) Provide some util functions for quick read, write, encode, decode JSON data.
|
||||
- [`byteutil`](byteutil): Provide some common bytes util functions. eg: convert, check and more
|
||||
- [`maputil`](maputil) Map data util functions. eg: convert, sub-value get, simple merge
|
||||
- [`mathutil`](mathutil) Math(int, number) util functions. eg: convert, math calc, random
|
||||
- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc.
|
||||
- [`reflects`](reflects) Provide extends reflect util functions.
|
||||
- [`structs`](structs) Provide some extends util functions for struct. eg: tag parse, struct data init
|
||||
- [`strutil`](strutil) String util functions. eg: bytes, check, convert, encode, format and more
|
||||
- [`sysutil`](sysutil) System util functions. eg: sysenv, exec, user, process
|
||||
- [`cliutil`](cliutil) Command-line util functions. eg: colored print, read input, exec command
|
||||
- [`envutil`](envutil) ENV util for current runtime env information. eg: get one, get info, parse var
|
||||
- [`fsutil`](fsutil) Filesystem util functions, quick create, read and write file. eg: file and dir check, operate
|
||||
- [`jsonutil`](jsonutil) Provide some util functions for quick read, write, encode, decode JSON data.
|
||||
|
||||
**Extra packages:**
|
||||
### Debug & Test & Errors
|
||||
|
||||
- [`dump`](dump): GO value printing tool. print slice, map will auto wrap each element and display the call location
|
||||
- [`errorx`](errorx) Provide an enhanced error implements for go, allow with stacktrace and wrap another error.
|
||||
- [`assert`](testutil/assert) Provides commonly asserts functions for help testing
|
||||
- [`testutil`](testutil) Test help util functions. eg: http test, mock ENV value
|
||||
- [`fakeobj`](x/fakeobj) provides a fake object for testing. such as fake fs.File, fs.FileInfo, fs.DirEntry etc.
|
||||
|
||||
### Extra Tools packages
|
||||
|
||||
- [`cflag`](cflag): Wraps and extends go `flag.FlagSet` to build simple command line applications
|
||||
- cli util:
|
||||
- [cmdline](cliutil/cmdline) Provide cmdline parse, args build to cmdline
|
||||
- [`dump`](dump): GO value printing tool. print slice, map will auto wrap each element and display the call location
|
||||
- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`errorx`](errorx) Provide an enhanced error implements for go, allow with stacktrace and wrap another error.
|
||||
- file util:
|
||||
- [`finder`](fsutil/finder) Provides a simple and convenient filedir lookup function, supports filtering, excluding, matching, ignoring, etc.
|
||||
- net util:
|
||||
- [httpreq](netutil/httpreq) An easier-to-use HTTP client that wraps http.Client, and with some http utils.
|
||||
- string util:
|
||||
- [textscan](strutil/textscan) Implemented a parser that quickly scans and analyzes text content. It can be used to parse INI, Properties and other formats
|
||||
- [textutil](strutil/textutil) Provide some extensions text handle util functions. eg: text replace, etc.
|
||||
- [syncs](syncs) Provides synchronization primitives util functions.
|
||||
- system util:
|
||||
- [clipboard](sysutil/clipboard) Provide a simple clipboard read and write operations.
|
||||
- [cmdr](sysutil/cmdr) Provide for quick build and run a cmd, batch run multi cmd tasks
|
||||
- [process](sysutil/process) Provide some process handle util functions.
|
||||
- [`testutil`](testutil) Test help util functions. eg: http test, mock ENV value
|
||||
- [assert](testutil/assert) Provides commonly asserts functions for help testing
|
||||
- [fakeobj](testutil/fakeobj) provides a fake object for testing. such as fake fs.File, fs.FileInfo, fs.DirEntry etc.
|
||||
- [`ccolor`](x/ccolor): Simple command-line color output library that uses ANSI color codes to output text with colors.
|
||||
- [`timex`](timex) Provides an enhanced time.Time implementation. Add more commonly used functional methods
|
||||
- Provides datetime format parsing like `Y-m-d H:i:s`
|
||||
- such as: DayStart(), DayAfter(), DayAgo(), DateFormat() and more.
|
||||
- [httpreq](netutil/httpreq) An easier-to-use HTTP client that wraps http.Client, and with some http utils.
|
||||
- [syncs](syncs) Provides synchronization primitives util functions.
|
||||
|
||||
**More ...**
|
||||
|
||||
- [`cmdline`](cliutil/cmdline) Provide cmdline parse, args build to cmdline
|
||||
- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`finder`](x/finder) Provides a simple and convenient file/dir lookup function, supports filtering, excluding, matching, ignoring, etc.
|
||||
- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc.
|
||||
- [textutil](strutil/textutil) Provide some extensions text handle util functions. eg: text replace, etc.
|
||||
- [textscan](strutil/textscan) Implemented a parser that quickly scans and analyzes text content. It can be used to parse INI, Properties and other formats
|
||||
- [`cmdr`](sysutil/cmdr) Provide for quick build and run a cmd, batch run multi cmd tasks
|
||||
- [`clipboard`](x/clipboard) Provide a simple clipboard read and write operations.
|
||||
- [`process`](sysutil/process) Provide some process handle util functions.
|
||||
- [`fmtutil`](x/fmtutil) Format data util functions. eg: data, size, time
|
||||
- [`goinfo`](x/goinfo) provide some standard util functions for go.
|
||||
|
||||
## Go Doc
|
||||
|
||||
Please see [Go doc](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
Please see [Go doc](https://pkg.go.dev/github.com/gookit/goutil).
|
||||
Wiki docs on [DeepWiki - gookit/goutil](https://deepwiki.com/gookit/goutil)
|
||||
|
||||
## Install
|
||||
|
||||
@@ -166,8 +173,9 @@ func Remove[T comdef.Compared](ls []T, val T) []T
|
||||
func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T
|
||||
func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V
|
||||
func Unique[T ~string | comdef.XintOrFloat](list []T) []T
|
||||
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int
|
||||
func Unique[T comdef.NumberOrString](list []T) []T
|
||||
func IndexOf[T comdef.NumberOrString](val T, list []T) int
|
||||
func FirstOr[T any](list []T, defVal ...T) T
|
||||
// source at arrutil/strings.go
|
||||
func StringsToAnys(ss []string) []any
|
||||
func StringsToSlice(ss []string) []any
|
||||
@@ -212,6 +220,7 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"}
|
||||
func NewBuffer() *Buffer
|
||||
// source at byteutil/byteutil.go
|
||||
func Md5(src any) []byte
|
||||
func Md5Sum(src any) []byte
|
||||
func ShortMd5(src any) []byte
|
||||
func Random(length int) ([]byte, error)
|
||||
func FirstLine(bs []byte) []byte
|
||||
@@ -221,6 +230,7 @@ func SafeCut(bs []byte, sep byte) (before, after []byte)
|
||||
func SafeCuts(bs []byte, sep []byte) (before, after []byte)
|
||||
// source at byteutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsAlphaChar(c byte) bool
|
||||
// source at byteutil/conv.go
|
||||
func StrOrErr(bs []byte, err error) (string, error)
|
||||
func SafeString(bs []byte, err error) string
|
||||
@@ -242,7 +252,7 @@ func NewChanPool(chSize int, width int, capWidth int) *ChanPool
|
||||
```go
|
||||
// source at cflag/app.go
|
||||
func NewApp(fns ...func(app *App)) *App
|
||||
func NewCmd(name, desc string) *Cmd
|
||||
func NewCmd(name, desc string, runFunc ...func(c *Cmd) error) *Cmd
|
||||
// source at cflag/cflag.go
|
||||
func SetDebug(open bool)
|
||||
func New(fns ...func(c *CFlags)) *CFlags
|
||||
@@ -275,7 +285,7 @@ func ReplaceShorts(args []string, shortsMap map[string]string) []string
|
||||
`cflag` usage please see [cflag/README.md](cflag/README.md)
|
||||
|
||||
|
||||
### CLI/Console
|
||||
### CLI Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/cliutil`
|
||||
|
||||
@@ -371,7 +381,7 @@ Build line: ./myapp -a val0 -m "this is message" arg0
|
||||
|
||||
> More, please see [./cliutil/README](cliutil/README.md)
|
||||
|
||||
### Dumper
|
||||
### Var Dumper
|
||||
|
||||
> Package `github.com/gookit/goutil/dump`
|
||||
|
||||
@@ -446,20 +456,6 @@ Preview:
|
||||

|
||||
|
||||
|
||||
### Encodes
|
||||
|
||||
> Package `github.com/gookit/goutil/encodes`
|
||||
|
||||
```go
|
||||
// source at encodes/encodes.go
|
||||
func B32Encode(str string) string
|
||||
func B32Decode(str string) string
|
||||
func B64Encode(str string) string
|
||||
func B64EncodeBytes(src []byte) []byte
|
||||
func B64Decode(str string) string
|
||||
func B64DecodeBytes(str []byte) []byte
|
||||
```
|
||||
|
||||
### ENV/Environment
|
||||
|
||||
> Package `github.com/gookit/goutil/envutil`
|
||||
@@ -471,14 +467,16 @@ func ParseOrErr(val string) (string, error)
|
||||
func ParseValue(val string) string
|
||||
func VarParse(val string) string
|
||||
func ParseEnvValue(val string) string
|
||||
func SetEnvMap(mp map[string]string)
|
||||
func SetEnvs(kvPairs ...string)
|
||||
func UnsetEnvs(keys ...string)
|
||||
func SplitText2map(text string) map[string]string
|
||||
func SplitLineToKv(line string) (string, string)
|
||||
// source at envutil/get.go
|
||||
func Getenv(name string, def ...string) string
|
||||
func MustGet(name string) string
|
||||
func GetInt(name string, def ...int) int
|
||||
func GetBool(name string, def ...bool) bool
|
||||
func GetOne(names []string, defVal ...string) string
|
||||
func GetMulti(names ...string) map[string]string
|
||||
func OnExist(name string, fn func(val string)) bool
|
||||
func EnvPaths() []string
|
||||
func EnvMap() map[string]string
|
||||
func Environ() map[string]string
|
||||
@@ -490,7 +488,6 @@ func IsWindows() bool
|
||||
func IsMac() bool
|
||||
func IsLinux() bool
|
||||
func IsMSys() bool
|
||||
func IsWSL() bool
|
||||
func IsTerminal(fd uintptr) bool
|
||||
func StdIsTerminal() bool
|
||||
func IsConsole(out io.Writer) bool
|
||||
@@ -499,6 +496,12 @@ func IsSupportColor() bool
|
||||
func IsSupport256Color() bool
|
||||
func IsSupportTrueColor() bool
|
||||
func IsGithubActions() bool
|
||||
// source at envutil/set.go
|
||||
func SetEnvMap(mp map[string]string)
|
||||
func SetEnvs(kvPairs ...string)
|
||||
func UnsetEnvs(keys ...string)
|
||||
func LoadText(text string)
|
||||
func LoadString(line string) bool
|
||||
```
|
||||
#### ENV Util Usage
|
||||
|
||||
@@ -562,7 +565,8 @@ func Err(msg string) error
|
||||
func Raw(msg string) error
|
||||
func Ef(tpl string, vars ...any) error
|
||||
func Errf(tpl string, vars ...any) error
|
||||
func Rawf(tpl string, vars ...any) error
|
||||
func Rf(tpl string, vs ...any) error
|
||||
func Rawf(tpl string, vs ...any) error
|
||||
func Cause(err error) error
|
||||
func Unwrap(err error) error
|
||||
func Previous(err error) error
|
||||
@@ -651,24 +655,6 @@ runtime.goexit()
|
||||
```
|
||||
|
||||
|
||||
### Format Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/fmtutil`
|
||||
|
||||
```go
|
||||
// source at fmtutil/fmtutil.go
|
||||
func StringOrJSON(v any) ([]byte, error)
|
||||
// source at fmtutil/format.go
|
||||
func DataSize(size uint64) string
|
||||
func SizeToString(size uint64) string
|
||||
func StringToByte(sizeStr string) uint64
|
||||
func ParseByte(sizeStr string) uint64
|
||||
func PrettyJSON(v any) (string, error)
|
||||
func ArgsWithSpaces(vs []any) (message string)
|
||||
// source at fmtutil/time.go
|
||||
func HowLongAgo(sec int64) string
|
||||
```
|
||||
|
||||
### File System
|
||||
|
||||
> Package `github.com/gookit/goutil/fsutil`
|
||||
@@ -688,7 +674,7 @@ func PathMatch(pattern, s string) bool
|
||||
func NewEntry(fPath string, ent fs.DirEntry) Entry
|
||||
func NewFileInfo(fPath string, info fs.FileInfo) FileInfo
|
||||
// source at fsutil/find.go
|
||||
func FilePathInDirs(file string, dirs ...string) string
|
||||
func FilePathInDirs(fPath string, dirs ...string) string
|
||||
func FirstExists(paths ...string) string
|
||||
func FirstExistsDir(paths ...string) string
|
||||
func FirstExistsFile(paths ...string) string
|
||||
@@ -707,20 +693,25 @@ func ExcludeDotFile(_ string, ent fs.DirEntry) bool
|
||||
func ExcludeSuffix(ss ...string) FilterFunc
|
||||
func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool
|
||||
func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error)
|
||||
func FileInDirs(paths []string, names ...string) string
|
||||
// source at fsutil/fsutil.go
|
||||
func JoinPaths(elem ...string) string
|
||||
func JoinSubPaths(basePath string, elem ...string) string
|
||||
func JoinPaths3(basePath, secPath string, elems ...string) string
|
||||
func JoinSubPaths(basePath string, elems ...string) string
|
||||
func SlashPath(path string) string
|
||||
func UnixPath(path string) string
|
||||
func ToAbsPath(p string) string
|
||||
func Must2(_ any, err error)
|
||||
// source at fsutil/info.go
|
||||
func DirPath(fpath string) string
|
||||
func Dir(fpath string) string
|
||||
func PathName(fpath string) string
|
||||
func Name(fpath string) string
|
||||
func FileExt(fpath string) string
|
||||
func Extname(fpath string) string
|
||||
func Suffix(fpath string) string
|
||||
func DirPath(fPath string) string
|
||||
func Dir(fPath string) string
|
||||
func PathName(fPath string) string
|
||||
func PathNoExt(fPath string) string
|
||||
func Name(fPath string) string
|
||||
func NameNoExt(fPath string) string
|
||||
func FileExt(fPath string) string
|
||||
func Extname(fPath string) string
|
||||
func Suffix(fPath string) string
|
||||
func Expand(pathStr string) string
|
||||
func ExpandPath(pathStr string) string
|
||||
func ResolvePath(pathStr string) string
|
||||
@@ -781,6 +772,7 @@ func OSTempDir(pattern string) (string, error)
|
||||
func TempDir(dir, pattern string) (string, error)
|
||||
func MustSave(filePath string, data any, optFns ...OpenOptionFunc)
|
||||
func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error
|
||||
func WriteData(filePath string, data any, fileFlag ...int) (int, error)
|
||||
func PutContents(filePath string, data any, fileFlag ...int) (int, error)
|
||||
func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error
|
||||
func WriteOSFile(f *os.File, data any) (n int, err error)
|
||||
@@ -819,27 +811,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### Go Info
|
||||
|
||||
> Package `github.com/gookit/goutil/goinfo`
|
||||
|
||||
```go
|
||||
// source at goinfo/gofunc.go
|
||||
func FuncName(fn any) string
|
||||
func CutFuncName(fullFcName string) (pkgPath, shortFnName string)
|
||||
func PkgName(fullFcName string) string
|
||||
func GoodFuncName(name string) bool
|
||||
// source at goinfo/goinfo.go
|
||||
func GoVersion() string
|
||||
func ParseGoVersion(line string) (*GoInfo, error)
|
||||
func OsGoInfo() (*GoInfo, error)
|
||||
// source at goinfo/stack.go
|
||||
func GetCallStacks(all bool) []byte
|
||||
func GetCallerInfo(skip int) string
|
||||
func SimpleCallersInfo(skip, num int) []string
|
||||
func GetCallersInfo(skip, max int) []string
|
||||
```
|
||||
|
||||
### JSON Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/jsonutil`
|
||||
@@ -855,6 +826,7 @@ func EncodeUnescapeHTML(v any) ([]byte, error)
|
||||
func Decode(bts []byte, ptr any) error
|
||||
func DecodeString(str string, ptr any) error
|
||||
func DecodeReader(r io.Reader, ptr any) error
|
||||
func DecodeFile(file string, ptr any) error
|
||||
// source at jsonutil/jsonutil.go
|
||||
func WriteFile(filePath string, data any) error
|
||||
func WritePretty(filePath string, data any) error
|
||||
@@ -880,9 +852,14 @@ func HasOneKey(mp any, keys ...any) (ok bool, key any)
|
||||
func HasAllKeys(mp any, keys ...any) (ok bool, noKey any)
|
||||
// source at maputil/convert.go
|
||||
func KeyToLower(src map[string]string) map[string]string
|
||||
func AnyToStrMap(src any) map[string]string
|
||||
func ToStringMap(src map[string]any) map[string]string
|
||||
func ToL2StringMap(groupsMap map[string]any) map[string]map[string]string
|
||||
func CombineToSMap(keys, values []string) SMap
|
||||
func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V
|
||||
func SliceToSMap(kvPairs ...string) map[string]string
|
||||
func SliceToMap(kvPairs ...any) map[string]any
|
||||
func SliceToTypeMap[T any](valFunc func(any) T, kvPairs ...any) map[string]T
|
||||
func ToAnyMap(mp any) map[string]any
|
||||
func TryAnyMap(mp any) (map[string]any, error)
|
||||
func HTTPQueryString(data map[string]any) string
|
||||
@@ -901,14 +878,21 @@ func GetFromAny(path string, data any) (val any, ok bool)
|
||||
func GetByPath(path string, mp map[string]any) (val any, ok bool)
|
||||
func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool)
|
||||
func Keys(mp any) (keys []string)
|
||||
func TypedKeys[K comdef.SimpleType, V any](mp map[K]V) (keys []K)
|
||||
func FirstKey[T any](mp map[string]T) string
|
||||
func Values(mp any) (values []any)
|
||||
func TypedValues[K comdef.SimpleType, V any](mp map[K]V) (values []V)
|
||||
func EachAnyMap(mp any, fn func(key string, val any))
|
||||
func EachTypedMap[K comdef.SimpleType, V any](mp map[K]V, fn func(key K, val V))
|
||||
// source at maputil/maputil.go
|
||||
func SimpleMerge(src, dst map[string]any) map[string]any
|
||||
func Merge1level(mps ...map[string]any) map[string]any
|
||||
func DeepMerge(src, dst map[string]any, deep int) map[string]any
|
||||
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeStrMap(src, dst map[string]string) map[string]string
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeMultiSMap(mps ...map[string]string) map[string]string
|
||||
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string
|
||||
func FilterSMap(sm map[string]string) map[string]string
|
||||
func MakeByPath(path string, val any) (mp map[string]any)
|
||||
func MakeByKeys(keys []string, val any) (mp map[string]any)
|
||||
@@ -922,21 +906,23 @@ func SetByKeys(mp *map[string]any, keys []string, val any) (err error)
|
||||
> Package `github.com/gookit/goutil/mathutil`
|
||||
|
||||
```go
|
||||
// source at mathutil/calc.go
|
||||
func Abs[T comdef.Int](val T) T
|
||||
// source at mathutil/check.go
|
||||
func IsNumeric(c byte) bool
|
||||
func Compare(first, second any, op string) bool
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool)
|
||||
func CompInt64(first, second int64, op string) bool
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool)
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool)
|
||||
func InRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func OutRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func CompValue[T comdef.Number](first, second T, op string) (ok bool)
|
||||
func InRange[T comdef.Number](val, min, max T) bool
|
||||
func OutRange[T comdef.Number](val, min, max T) bool
|
||||
func InUintRange[T comdef.Uint](val, min, max T) bool
|
||||
// source at mathutil/compare.go
|
||||
func Min[T comdef.XintOrFloat](x, y T) T
|
||||
func Max[T comdef.XintOrFloat](x, y T) T
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func Min[T comdef.Number](x, y T) T
|
||||
func Max[T comdef.Number](x, y T) T
|
||||
func SwapMin[T comdef.Number](x, y T) (T, T)
|
||||
func SwapMax[T comdef.Number](x, y T) (T, T)
|
||||
func MaxInt(x, y int) int
|
||||
func SwapMaxInt(x, y int) (int, int)
|
||||
func MaxI64(x, y int64) int64
|
||||
@@ -1011,15 +997,15 @@ func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
|
||||
func DataSize(size uint64) string
|
||||
func HowLongAgo(sec int64) string
|
||||
// source at mathutil/mathutil.go
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
|
||||
func OrElse[T comdef.Number](val, defVal T) T
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T
|
||||
func LessOr[T comdef.Number](val, max, devVal T) T
|
||||
func LteOr[T comdef.Number](val, max, devVal T) T
|
||||
func GreaterOr[T comdef.Number](val, min, defVal T) T
|
||||
func GteOr[T comdef.Number](val, min, defVal T) T
|
||||
func Mul[T1, T2 comdef.Number](a T1, b T2) float64
|
||||
func MulF2i(a, b float64) int
|
||||
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
|
||||
func Div[T1, T2 comdef.Number](a T1, b T2) float64
|
||||
func DivInt[T comdef.Integer](a, b T) int
|
||||
func DivF2i(a, b float64) int
|
||||
func Percent(val, total int) float64
|
||||
@@ -1028,8 +1014,6 @@ func RandomInt(min, max int) int
|
||||
func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
// source at mathutil/value.go
|
||||
func New[T comdef.IntOrFloat](v T) *Num[T]
|
||||
```
|
||||
|
||||
### Reflects
|
||||
@@ -1038,6 +1022,8 @@ func New[T comdef.IntOrFloat](v T) *Num[T]
|
||||
|
||||
```go
|
||||
// source at reflects/check.go
|
||||
func IsTimeType(t reflect.Type) bool
|
||||
func IsDurationType(t reflect.Type) bool
|
||||
func HasChild(v reflect.Value) bool
|
||||
func IsArrayOrSlice(k reflect.Kind) bool
|
||||
func IsSimpleKind(k reflect.Kind) bool
|
||||
@@ -1046,6 +1032,7 @@ func IsIntLike(k reflect.Kind) bool
|
||||
func IsIntx(k reflect.Kind) bool
|
||||
func IsUintX(k reflect.Kind) bool
|
||||
func IsNil(v reflect.Value) bool
|
||||
func IsValidPtr(v reflect.Value) bool
|
||||
func CanBeNil(typ reflect.Type) bool
|
||||
func IsFunc(val any) bool
|
||||
func IsEqual(src, dst any) bool
|
||||
@@ -1056,12 +1043,13 @@ func BaseTypeVal(v reflect.Value) (value any, err error)
|
||||
func ToBaseVal(v reflect.Value) (value any, err error)
|
||||
func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error)
|
||||
func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error)
|
||||
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error)
|
||||
func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error)
|
||||
func ValueByKind(val any, kind reflect.Kind) (reflect.Value, error)
|
||||
func ConvToKind(val any, kind reflect.Kind, fallback ...ConvFunc) (rv reflect.Value, err error)
|
||||
func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error)
|
||||
func String(rv reflect.Value) string
|
||||
func ToString(rv reflect.Value) (str string, err error)
|
||||
func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error)
|
||||
func ToTimeOrDuration(str string, typ reflect.Type) (any, error)
|
||||
// source at reflects/func.go
|
||||
func NewFunc(fn any) *FuncX
|
||||
func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error)
|
||||
@@ -1069,8 +1057,9 @@ func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value
|
||||
func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error)
|
||||
func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error)
|
||||
// source at reflects/map.go
|
||||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value))
|
||||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any))
|
||||
func TryAnyMap(mp reflect.Value) (map[string]any, error)
|
||||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) (err error)
|
||||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) error
|
||||
func FlatMap(rv reflect.Value, fn FlatFunc)
|
||||
// source at reflects/slice.go
|
||||
func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value
|
||||
@@ -1097,32 +1086,6 @@ func Wrap(rv reflect.Value) Value
|
||||
func ValueOf(v any) Value
|
||||
```
|
||||
|
||||
### Stdio
|
||||
|
||||
> Package `github.com/gookit/goutil/stdio`
|
||||
|
||||
```go
|
||||
// source at stdio/ioutil.go
|
||||
func QuietFprint(w io.Writer, a ...any)
|
||||
func QuietFprintf(w io.Writer, tpl string, vs ...any)
|
||||
func QuietFprintln(w io.Writer, a ...any)
|
||||
func QuietWriteString(w io.Writer, ss ...string)
|
||||
// source at stdio/stdio.go
|
||||
func DiscardReader(src io.Reader)
|
||||
func ReadString(r io.Reader) string
|
||||
func MustReadReader(r io.Reader) []byte
|
||||
func NewIOReader(in any) io.Reader
|
||||
func NewScanner(in any) *bufio.Scanner
|
||||
func WriteByte(b byte)
|
||||
func WriteBytes(bs []byte)
|
||||
func WritelnBytes(bs []byte)
|
||||
func WriteString(s string)
|
||||
func Writeln(s string)
|
||||
// source at stdio/writer.go
|
||||
func WrapW(w io.Writer) *WriteWrapper
|
||||
func NewWriteWrapper(w io.Writer) *WriteWrapper
|
||||
```
|
||||
|
||||
### Structs
|
||||
|
||||
> Package `github.com/gookit/goutil/structs`
|
||||
@@ -1139,8 +1102,10 @@ func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error)
|
||||
func MustToSMap(st any, optFns ...MapOptFunc) map[string]string
|
||||
func ToString(st any, optFns ...MapOptFunc) string
|
||||
func WithMapTagName(tagName string) MapOptFunc
|
||||
func WithUserFunc(fn CustomUserFunc) MapOptFunc
|
||||
func MergeAnonymous(opt *MapOptions)
|
||||
func ExportPrivate(opt *MapOptions)
|
||||
func WithIgnoreEmpty(opt *MapOptions)
|
||||
func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error)
|
||||
// source at structs/copy.go
|
||||
func MapStruct(srcSt, dstSt any)
|
||||
@@ -1171,6 +1136,8 @@ func WrapValue(rv reflect.Value) *Wrapper
|
||||
// source at structs/writer.go
|
||||
func NewWriter(ptr any) *Wrapper
|
||||
func WithParseDefault(opt *SetOptions)
|
||||
func WithBeforeSetFn(fn BeforeSetFunc) SetOptFunc
|
||||
func BindData(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
```
|
||||
|
||||
@@ -1180,10 +1147,12 @@ func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
|
||||
```go
|
||||
// source at strutil/bytes.go
|
||||
func NewBuffer() *Buffer
|
||||
func NewBuffer(initSize ...int) *Buffer
|
||||
func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool
|
||||
// source at strutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsInt(s string) bool
|
||||
func IsFloat(s string) bool
|
||||
func IsNumeric(s string) bool
|
||||
func IsAlphabet(char uint8) bool
|
||||
func IsAlphaNum(c uint8) bool
|
||||
@@ -1195,8 +1164,10 @@ func IContains(s, sub string) bool
|
||||
func ContainsByte(s string, c byte) bool
|
||||
func ContainsOne(s string, subs []string) bool
|
||||
func HasOneSub(s string, subs []string) bool
|
||||
func IContainsOne(s string, subs []string) bool
|
||||
func ContainsAll(s string, subs []string) bool
|
||||
func HasAllSubs(s string, subs []string) bool
|
||||
func IContainsAll(s string, subs []string) bool
|
||||
func IsStartsOf(s string, prefixes []string) bool
|
||||
func HasOnePrefix(s string, prefixes []string) bool
|
||||
func HasPrefix(s string, prefix string) bool
|
||||
@@ -1214,6 +1185,7 @@ func IsSymbol(r rune) bool
|
||||
func HasEmpty(ss ...string) bool
|
||||
func IsAllEmpty(ss ...string) bool
|
||||
func IsVersion(s string) bool
|
||||
func IsVarName(s string) bool
|
||||
func Compare(s1, s2, op string) bool
|
||||
func VersionCompare(v1, v2, op string) bool
|
||||
func SimpleMatch(s string, keywords []string) bool
|
||||
@@ -1231,6 +1203,7 @@ func Quote(s string) string
|
||||
func Unquote(s string) string
|
||||
func Join(sep string, ss ...string) string
|
||||
func JoinList(sep string, ss []string) string
|
||||
func JoinComma(ss []string) string
|
||||
func JoinAny(sep string, parts ...any) string
|
||||
func Implode(sep string, ss ...string) string
|
||||
func String(val any) (string, error)
|
||||
@@ -1330,6 +1303,7 @@ func IndentBytes(b, prefix []byte) []byte
|
||||
func MicroTimeID() string
|
||||
func MicroTimeHexID() string
|
||||
func MTimeHexID() string
|
||||
func MTimeBase36() string
|
||||
func MTimeBaseID(toBase int) string
|
||||
func DatetimeNo(prefix string) string
|
||||
func DateSN(prefix string) string
|
||||
@@ -1338,6 +1312,8 @@ func DateSNV2(prefix string, extBase ...int) string
|
||||
func Md5(src any) string
|
||||
func MD5(src any) string
|
||||
func GenMd5(src any) string
|
||||
func Md5Simple(src any) string
|
||||
func Md5Base62(src any) string
|
||||
func Md5Bytes(src any) []byte
|
||||
func ShortMd5(src any) string
|
||||
func HashPasswd(pwd, key string) string
|
||||
@@ -1387,6 +1363,7 @@ func RunesWidth(rs []rune) (w int)
|
||||
func Truncate(s string, w int, tail string) string
|
||||
func TextTruncate(s string, w int, tail string) string
|
||||
func Utf8Truncate(s string, w int, tail string) string
|
||||
func Chunk[T ~string](s T, size int) []T
|
||||
func TextSplit(s string, w int) []string
|
||||
func Utf8Split(s string, w int) []string
|
||||
func TextWrap(s string, w int) string
|
||||
@@ -1408,6 +1385,7 @@ func SplitNValid(s, sep string, n int) (ss []string)
|
||||
func SplitN(s, sep string, n int) (ss []string)
|
||||
func SplitTrimmed(s, sep string) (ss []string)
|
||||
func SplitNTrimmed(s, sep string, n int) (ss []string)
|
||||
func SplitByWhitespace(s string) []string
|
||||
func Substr(s string, pos, length int) string
|
||||
func SplitInlineComment(val string, strict ...bool) (string, string)
|
||||
func FirstLine(output string) string
|
||||
@@ -1432,12 +1410,12 @@ func SubstrCount(s, substr string, params ...uint64) (int, error)
|
||||
|
||||
```go
|
||||
// source at syncs/chan.go
|
||||
func WaitCloseSignals(onClose func(sig os.Signal))
|
||||
func Go(f func() error) error
|
||||
// source at syncs/group.go
|
||||
func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context)
|
||||
func NewErrGroup(limit ...int) *ErrGroup
|
||||
// source at syncs/signal.go
|
||||
func WaitCloseSignals(onClose func(sig os.Signal), sigCh ...chan os.Signal)
|
||||
func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error))
|
||||
```
|
||||
|
||||
@@ -1453,15 +1431,14 @@ func QuickExec(cmdLine string, workDir ...string) (string, error)
|
||||
func ExecLine(cmdLine string, workDir ...string) (string, error)
|
||||
func ExecCmd(binName string, args []string, workDir ...string) (string, error)
|
||||
func ShellExec(cmdLine string, shells ...string) (string, error)
|
||||
// source at sysutil/stack.go
|
||||
func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo
|
||||
// source at sysutil/sysenv.go
|
||||
func IsMSys() bool
|
||||
func IsWSL() bool
|
||||
func IsConsole(out io.Writer) bool
|
||||
func IsTerminal(fd uintptr) bool
|
||||
func StdIsTerminal() bool
|
||||
func Hostname() string
|
||||
func CurrentShell(onlyName bool) (path string)
|
||||
func CurrentShell(onlyName bool, fallbackShell ...string) string
|
||||
func HasShellEnv(shell string) bool
|
||||
func IsShellSpecialVar(c uint8) bool
|
||||
func FindExecutable(binName string) (string, error)
|
||||
@@ -1471,11 +1448,13 @@ func Getenv(name string, def ...string) string
|
||||
func Environ() map[string]string
|
||||
func EnvMapWith(newEnv map[string]string) map[string]string
|
||||
func EnvPaths() []string
|
||||
func SearchPath(keywords string, limit int) []string
|
||||
func ToEnvPATH(paths []string) string
|
||||
func SearchPath(keywords string, limit int, opts ...SearchPathOption) []string
|
||||
// source at sysutil/sysgo.go
|
||||
func GoVersion() string
|
||||
func ParseGoVersion(line string) (*GoInfo, error)
|
||||
func OsGoInfo() (*GoInfo, error)
|
||||
func CallersInfos(skip, num int, filters ...goinfo.CallerFilterFunc) []*CallerInfo
|
||||
// source at sysutil/sysutil.go
|
||||
func Workdir() string
|
||||
func BinDir() string
|
||||
@@ -1484,16 +1463,16 @@ func BinFile() string
|
||||
func Open(fileOrURL string) error
|
||||
func OpenBrowser(fileOrURL string) error
|
||||
func OpenFile(path string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
func Kill(pid int, signal syscall.Signal) error
|
||||
func ProcessExists(pid int) bool
|
||||
// source at sysutil/sysutil_unix.go
|
||||
// source at sysutil/sysutil_linux.go
|
||||
func IsWin() bool
|
||||
func IsWindows() bool
|
||||
func IsMac() bool
|
||||
func IsDarwin() bool
|
||||
func IsLinux() bool
|
||||
func OpenURL(URL string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
func Kill(pid int, signal syscall.Signal) error
|
||||
func ProcessExists(pid int) bool
|
||||
// source at sysutil/user.go
|
||||
func MustFindUser(uname string) *user.User
|
||||
func LoginUser() *user.User
|
||||
@@ -1501,12 +1480,13 @@ func CurrentUser() *user.User
|
||||
func UHomeDir() string
|
||||
func UserHomeDir() string
|
||||
func HomeDir() string
|
||||
func UserDir(subPath string) string
|
||||
func UserCacheDir(subPath string) string
|
||||
func UserConfigDir(subPath string) string
|
||||
func UserDir(subPaths ...string) string
|
||||
func UserCacheDir(subPaths ...string) string
|
||||
func UserConfigDir(subPaths ...string) string
|
||||
func ExpandPath(path string) string
|
||||
func ExpandHome(path string) string
|
||||
// source at sysutil/user_nonwin.go
|
||||
func IsAdmin() bool
|
||||
func ChangeUserByName(newUname string) error
|
||||
func ChangeUserUidGid(newUID int, newGid int) error
|
||||
func ChangeUserUIDGid(newUID int, newGid int) (err error)
|
||||
@@ -1524,15 +1504,18 @@ func MockEnvValue(key, val string, fn func(nv string))
|
||||
func MockEnvValues(kvMap map[string]string, fn func())
|
||||
func MockOsEnvByText(envText string, fn func())
|
||||
func MockOsEnv(mp map[string]string, fn func())
|
||||
func SetOsEnvs(mp map[string]string) string
|
||||
func RemoveTmpEnvs(tmpKey string)
|
||||
func ClearOSEnv()
|
||||
func RevertOSEnv()
|
||||
func RunOnCleanEnv(runFn func())
|
||||
func MockCleanOsEnv(mp map[string]string, fn func())
|
||||
// source at testutil/httpmock.go
|
||||
func NewHttpRequest(method, path string, data *MD) *http.Request
|
||||
func NewHTTPRequest(method, path string, data *MD) *http.Request
|
||||
func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder
|
||||
func MockHttpServer() *EchoServer
|
||||
func TestMain(m *testing.M)
|
||||
func NewEchoServer() *httptest.Server
|
||||
func NewEchoServer() *EchoServer
|
||||
func BuildEchoReply(r *http.Request) *EchoReply
|
||||
func ParseRespToReply(w *http.Response) *EchoReply
|
||||
func ParseBodyToReply(bd io.ReadCloser) *EchoReply
|
||||
@@ -1548,7 +1531,7 @@ func SetTimeLocalUTC()
|
||||
func RestoreTimeLocal()
|
||||
// source at testutil/writer.go
|
||||
func NewTestWriter() *TestWriter
|
||||
func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry
|
||||
func NewDirEnt(fPath string, isDir ...bool) *fakeobj.DirEntry
|
||||
```
|
||||
|
||||
### Timex
|
||||
@@ -1752,17 +1735,14 @@ Testing in docker:
|
||||
|
||||
```shell
|
||||
cd goutil
|
||||
docker run -ti -v $(pwd):/go/work golang:1.18
|
||||
root@xx:/go/work# go test ./...
|
||||
|
||||
docker run -ti -v $(pwd):/go/goutil -e GOPROXY=https://goproxy.cn,direct golang:1.23
|
||||
# on Windows
|
||||
docker run -ti -v "${PWD}:/go/goutil" -e GOPROXY=https://goproxy.cn,direct golang:1.23
|
||||
|
||||
root@xx:/go/goutil# go test ./...
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- https://github.com/duke-git/lancet
|
||||
- https://github.com/samber/lo
|
||||
- https://github.com/zyedidia/generic
|
||||
- https://github.com/thoas/go-funk
|
||||
|
||||
## Gookit packages
|
||||
|
||||
- [gookit/ini](https://github.com/gookit/ini) Go config management, use INI files
|
||||
@@ -1778,6 +1758,13 @@ root@xx:/go/work# go test ./...
|
||||
- [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
|
||||
|
||||
## Related
|
||||
|
||||
- https://github.com/duke-git/lancet
|
||||
- https://github.com/samber/lo
|
||||
- https://github.com/zyedidia/generic
|
||||
- https://github.com/thoas/go-funk
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
322
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
322
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
@@ -7,55 +7,63 @@
|
||||
[](https://coveralls.io/github/gookit/goutil?branch=master)
|
||||
[](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
`goutil` Go 常用功能的扩展工具库(**700+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。
|
||||
`goutil` Go 常用功能的扩展工具库(**800+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。
|
||||
|
||||
> **[EN README](README.md)**
|
||||
|
||||
**基础工具包**
|
||||
## 工具包说明
|
||||
|
||||
### 基础工具包
|
||||
|
||||
- [`arrutil`](arrutil) array/slice 相关操作的函数工具包 如:类型转换,元素检查等等
|
||||
- [`cliutil`](cliutil) CLI 的一些工具函数包. eg: read input, exec command
|
||||
- [cmdline](cliutil/cmdline) 提供 cmdline 解析,args 构建到 cmdline
|
||||
- [`envutil`](envutil) ENV 信息获取判断工具包. eg: get one, get info, parse var
|
||||
- [`fmtutil`](fmtutil) 格式化数据工具函数 eg:数据size
|
||||
- [`fsutil`](fsutil) 文件系统操作相关的工具函数包. eg: file and dir check, operate
|
||||
- [`goinfo`](goinfo) 提供一些与Go info, runtime 相关的工具函数。
|
||||
- [`jsonutil`](jsonutil) 一些用于快速读取、写入、编码、解码 JSON 数据的实用函数。
|
||||
- [`byteutil`](byteutil): 提供一些常用的 byte 操作函数工具包. eg: convert, check and more
|
||||
- [`maputil`](maputil) map 相关操作的函数工具包. eg: convert, sub-value get, simple merge
|
||||
- [`mathutil`](mathutil) int/number 相关操作的函数工具包. eg: convert, math calc, random
|
||||
- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc.
|
||||
- [`reflects`](reflects) 提供一些扩展性的反射使用工具函数.
|
||||
- [`structs`](structs) 为 struct 提供一些扩展 util 函数。 eg: tag parse, struct data
|
||||
- [`strutil`](strutil) string 相关操作的函数工具包. eg: bytes, check, convert, encode, format and more
|
||||
- [`cliutil`](cliutil) CLI 的一些工具函数包. eg: read input, exec command
|
||||
- [`envutil`](envutil) ENV 信息获取判断工具包. eg: get one, get info, parse var
|
||||
- [`fsutil`](fsutil) 文件系统操作相关的工具函数包. eg: file and dir check, operate
|
||||
- [`jsonutil`](jsonutil) 一些用于快速读取、写入、编码、解码 JSON 数据的实用函数。
|
||||
- [`sysutil`](sysutil) system 相关操作的函数工具包. eg: sysenv, exec, user, process
|
||||
|
||||
**扩展工具包**
|
||||
### Debug & Test & Errors
|
||||
|
||||
- [`cflag`](./cflag): 包装和扩展 go `flag.FlagSet` 以方便快速的构建简单的命令行应用程序
|
||||
- [`dump`](./dump) GO变量打印工具,打印 slice, map 会自动换行显示每个元素,同时会显示打印调用位置
|
||||
- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`errorx`](./errorx) 为 go 提供增强的错误实现,允许带有堆栈跟踪信息和包装另一个错误。
|
||||
- [`finder`](./fsutil/finder) 提供简单方便的file/dir查找功能,支持过滤、排除、匹配、忽略等。
|
||||
- netutil 子包:
|
||||
- `netutil/httpreq` 包装 http.Client 实现的更加易于使用的HTTP客户端, 和一些 http 工具函数
|
||||
- strutil 子包:
|
||||
- [textscan](strutil/textscan) 实现了一个快速扫描和分析文本内容的解析器. 可用于解析 INI, Properties 等格式内容
|
||||
- [textutil](strutil/textutil) 提供一些常用的扩展文本处理功能函数。
|
||||
- [syncs](syncs) 提供一些同步、协程、信号相关的工具函数.
|
||||
- sysutil 子包:
|
||||
- [clipboard](sysutil/clipboard) 提供简单的剪贴板读写操作工具库
|
||||
- [cmdr](sysutil/cmdr) 提供快速构建和运行一个cmd,批量运行多个cmd任务
|
||||
- [process](sysutil/process) 提供一些进程操作相关的实用功能。
|
||||
- [`testutil`](testutil) test help 相关操作的函数工具包. eg: http test, mock ENV value
|
||||
- [assert](testutil/assert) 用于帮助测试的断言函数工具包,方便编写单元测试。
|
||||
- [fakeobj](testutil/fakeobj) 提供一些接口的假的实现,用于模拟测试. 例如 fs.File, fs.FileInfo, fs.DirEntry 等等.
|
||||
- [`assert`](testutil/assert) 用于帮助测试的断言函数工具包,方便编写单元测试。
|
||||
- [`fakeobj`](x/fakeobj) 提供一些接口的MOCK的实现,用于模拟测试. 例如 fs.File, fs.FileInfo, fs.DirEntry 等等.
|
||||
|
||||
### 扩展工具包
|
||||
|
||||
- [`cflag`](cflag): 包装和扩展 go `flag.FlagSet` 以方便快速的构建简单的命令行应用程序
|
||||
- [`ccolor`](x/ccolor): 简单的命令行颜色输出库,它使用 ANSI 颜色代码来输出带有颜色的文本。
|
||||
- [`syncs`](syncs) 提供一些同步、协程、信号相关的工具函数.
|
||||
- [`httpreq`](netutil/httpreq) 包装 http.Client 实现的更加易于使用的HTTP客户端, 和一些 http 工具函数
|
||||
- [`clipboard`](sysutil/clipboard) 提供简单的OS剪贴板读写操作工具库
|
||||
- [`timex`](timex) 提供增强的 time.Time 实现。添加更多常用的功能方法
|
||||
- 提供类似 `Y-m-d H:i:s` 的日期时间格式解析处理
|
||||
- 常用时间方法。例如: DayStart(), DayAfter(), DayAgo(), DateFormat() 等等
|
||||
|
||||
**更多 ...**
|
||||
|
||||
- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc.
|
||||
- [`cmdline`](cliutil/cmdline) 提供 cmdline 解析,args 构建到 cmdline
|
||||
- [`encodes`](x/encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`finder`](x/finder) 提供简单方便的file/dir查找功能,支持过滤、排除、匹配、忽略等。
|
||||
- [textscan](strutil/textscan) 实现了一个快速扫描和分析文本内容的解析器. 可用于解析 INI, Properties 等格式内容
|
||||
- [textutil](strutil/textutil) 提供一些常用的扩展文本处理功能函数。
|
||||
- [cmdr](sysutil/cmdr) 提供快速构建和运行一个cmd,批量运行多个cmd任务
|
||||
- [process](sysutil/process) 提供一些进程操作相关的实用功能。
|
||||
- [`fmtutil`](x/fmtutil) 格式化数据工具函数 eg:数据size
|
||||
- [`goinfo`](x/goinfo) 提供一些与Go info, runtime 相关的工具函数。
|
||||
|
||||
## GoDoc
|
||||
|
||||
- [Godoc for github](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
- Wiki docs on [DeepWiki - gookit/goutil](https://deepwiki.com/gookit/goutil)
|
||||
|
||||
## 获取
|
||||
|
||||
@@ -95,7 +103,7 @@ dump.Print(somevar, somevar2, ...)
|
||||
|
||||

|
||||
|
||||
## Packages
|
||||
## Packages Details
|
||||
|
||||
### Array and Slice
|
||||
|
||||
@@ -165,8 +173,9 @@ func Remove[T comdef.Compared](ls []T, val T) []T
|
||||
func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T
|
||||
func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V
|
||||
func Unique[T ~string | comdef.XintOrFloat](list []T) []T
|
||||
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int
|
||||
func Unique[T comdef.NumberOrString](list []T) []T
|
||||
func IndexOf[T comdef.NumberOrString](val T, list []T) int
|
||||
func FirstOr[T any](list []T, defVal ...T) T
|
||||
// source at arrutil/strings.go
|
||||
func StringsToAnys(ss []string) []any
|
||||
func StringsToSlice(ss []string) []any
|
||||
@@ -211,6 +220,7 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"}
|
||||
func NewBuffer() *Buffer
|
||||
// source at byteutil/byteutil.go
|
||||
func Md5(src any) []byte
|
||||
func Md5Sum(src any) []byte
|
||||
func ShortMd5(src any) []byte
|
||||
func Random(length int) ([]byte, error)
|
||||
func FirstLine(bs []byte) []byte
|
||||
@@ -220,6 +230,7 @@ func SafeCut(bs []byte, sep byte) (before, after []byte)
|
||||
func SafeCuts(bs []byte, sep []byte) (before, after []byte)
|
||||
// source at byteutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsAlphaChar(c byte) bool
|
||||
// source at byteutil/conv.go
|
||||
func StrOrErr(bs []byte, err error) (string, error)
|
||||
func SafeString(bs []byte, err error) string
|
||||
@@ -241,7 +252,7 @@ func NewChanPool(chSize int, width int, capWidth int) *ChanPool
|
||||
```go
|
||||
// source at cflag/app.go
|
||||
func NewApp(fns ...func(app *App)) *App
|
||||
func NewCmd(name, desc string) *Cmd
|
||||
func NewCmd(name, desc string, runFunc ...func(c *Cmd) error) *Cmd
|
||||
// source at cflag/cflag.go
|
||||
func SetDebug(open bool)
|
||||
func New(fns ...func(c *CFlags)) *CFlags
|
||||
@@ -274,7 +285,7 @@ func ReplaceShorts(args []string, shortsMap map[string]string) []string
|
||||
`cflag` 使用说明请看 [cflag/README.zh-CN.md](cflag/README.zh-CN.md)
|
||||
|
||||
|
||||
### CLI/Console
|
||||
### CLI Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/cliutil`
|
||||
|
||||
@@ -370,7 +381,7 @@ Build line: ./myapp -a val0 -m "this is message" arg0
|
||||
|
||||
> More, please see [./cliutil/README](cliutil/README.md)
|
||||
|
||||
### Dumper
|
||||
### Var Dumper
|
||||
|
||||
> Package `github.com/gookit/goutil/dump`
|
||||
|
||||
@@ -445,20 +456,6 @@ Preview:
|
||||

|
||||
|
||||
|
||||
### Encodes
|
||||
|
||||
> Package `github.com/gookit/goutil/encodes`
|
||||
|
||||
```go
|
||||
// source at encodes/encodes.go
|
||||
func B32Encode(str string) string
|
||||
func B32Decode(str string) string
|
||||
func B64Encode(str string) string
|
||||
func B64EncodeBytes(src []byte) []byte
|
||||
func B64Decode(str string) string
|
||||
func B64DecodeBytes(str []byte) []byte
|
||||
```
|
||||
|
||||
### ENV/Environment
|
||||
|
||||
> Package `github.com/gookit/goutil/envutil`
|
||||
@@ -470,14 +467,16 @@ func ParseOrErr(val string) (string, error)
|
||||
func ParseValue(val string) string
|
||||
func VarParse(val string) string
|
||||
func ParseEnvValue(val string) string
|
||||
func SetEnvMap(mp map[string]string)
|
||||
func SetEnvs(kvPairs ...string)
|
||||
func UnsetEnvs(keys ...string)
|
||||
func SplitText2map(text string) map[string]string
|
||||
func SplitLineToKv(line string) (string, string)
|
||||
// source at envutil/get.go
|
||||
func Getenv(name string, def ...string) string
|
||||
func MustGet(name string) string
|
||||
func GetInt(name string, def ...int) int
|
||||
func GetBool(name string, def ...bool) bool
|
||||
func GetOne(names []string, defVal ...string) string
|
||||
func GetMulti(names ...string) map[string]string
|
||||
func OnExist(name string, fn func(val string)) bool
|
||||
func EnvPaths() []string
|
||||
func EnvMap() map[string]string
|
||||
func Environ() map[string]string
|
||||
@@ -489,7 +488,6 @@ func IsWindows() bool
|
||||
func IsMac() bool
|
||||
func IsLinux() bool
|
||||
func IsMSys() bool
|
||||
func IsWSL() bool
|
||||
func IsTerminal(fd uintptr) bool
|
||||
func StdIsTerminal() bool
|
||||
func IsConsole(out io.Writer) bool
|
||||
@@ -498,6 +496,12 @@ func IsSupportColor() bool
|
||||
func IsSupport256Color() bool
|
||||
func IsSupportTrueColor() bool
|
||||
func IsGithubActions() bool
|
||||
// source at envutil/set.go
|
||||
func SetEnvMap(mp map[string]string)
|
||||
func SetEnvs(kvPairs ...string)
|
||||
func UnsetEnvs(keys ...string)
|
||||
func LoadText(text string)
|
||||
func LoadString(line string) bool
|
||||
```
|
||||
#### ENV Util Usage
|
||||
|
||||
@@ -563,7 +567,8 @@ func Err(msg string) error
|
||||
func Raw(msg string) error
|
||||
func Ef(tpl string, vars ...any) error
|
||||
func Errf(tpl string, vars ...any) error
|
||||
func Rawf(tpl string, vars ...any) error
|
||||
func Rf(tpl string, vs ...any) error
|
||||
func Rawf(tpl string, vs ...any) error
|
||||
func Cause(err error) error
|
||||
func Unwrap(err error) error
|
||||
func Previous(err error) error
|
||||
@@ -652,24 +657,6 @@ runtime.goexit()
|
||||
```
|
||||
|
||||
|
||||
### Format Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/fmtutil`
|
||||
|
||||
```go
|
||||
// source at fmtutil/fmtutil.go
|
||||
func StringOrJSON(v any) ([]byte, error)
|
||||
// source at fmtutil/format.go
|
||||
func DataSize(size uint64) string
|
||||
func SizeToString(size uint64) string
|
||||
func StringToByte(sizeStr string) uint64
|
||||
func ParseByte(sizeStr string) uint64
|
||||
func PrettyJSON(v any) (string, error)
|
||||
func ArgsWithSpaces(vs []any) (message string)
|
||||
// source at fmtutil/time.go
|
||||
func HowLongAgo(sec int64) string
|
||||
```
|
||||
|
||||
### File System
|
||||
|
||||
> Package `github.com/gookit/goutil/fsutil`
|
||||
@@ -689,7 +676,7 @@ func PathMatch(pattern, s string) bool
|
||||
func NewEntry(fPath string, ent fs.DirEntry) Entry
|
||||
func NewFileInfo(fPath string, info fs.FileInfo) FileInfo
|
||||
// source at fsutil/find.go
|
||||
func FilePathInDirs(file string, dirs ...string) string
|
||||
func FilePathInDirs(fPath string, dirs ...string) string
|
||||
func FirstExists(paths ...string) string
|
||||
func FirstExistsDir(paths ...string) string
|
||||
func FirstExistsFile(paths ...string) string
|
||||
@@ -708,20 +695,25 @@ func ExcludeDotFile(_ string, ent fs.DirEntry) bool
|
||||
func ExcludeSuffix(ss ...string) FilterFunc
|
||||
func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool
|
||||
func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error)
|
||||
func FileInDirs(paths []string, names ...string) string
|
||||
// source at fsutil/fsutil.go
|
||||
func JoinPaths(elem ...string) string
|
||||
func JoinSubPaths(basePath string, elem ...string) string
|
||||
func JoinPaths3(basePath, secPath string, elems ...string) string
|
||||
func JoinSubPaths(basePath string, elems ...string) string
|
||||
func SlashPath(path string) string
|
||||
func UnixPath(path string) string
|
||||
func ToAbsPath(p string) string
|
||||
func Must2(_ any, err error)
|
||||
// source at fsutil/info.go
|
||||
func DirPath(fpath string) string
|
||||
func Dir(fpath string) string
|
||||
func PathName(fpath string) string
|
||||
func Name(fpath string) string
|
||||
func FileExt(fpath string) string
|
||||
func Extname(fpath string) string
|
||||
func Suffix(fpath string) string
|
||||
func DirPath(fPath string) string
|
||||
func Dir(fPath string) string
|
||||
func PathName(fPath string) string
|
||||
func PathNoExt(fPath string) string
|
||||
func Name(fPath string) string
|
||||
func NameNoExt(fPath string) string
|
||||
func FileExt(fPath string) string
|
||||
func Extname(fPath string) string
|
||||
func Suffix(fPath string) string
|
||||
func Expand(pathStr string) string
|
||||
func ExpandPath(pathStr string) string
|
||||
func ResolvePath(pathStr string) string
|
||||
@@ -782,6 +774,7 @@ func OSTempDir(pattern string) (string, error)
|
||||
func TempDir(dir, pattern string) (string, error)
|
||||
func MustSave(filePath string, data any, optFns ...OpenOptionFunc)
|
||||
func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error
|
||||
func WriteData(filePath string, data any, fileFlag ...int) (int, error)
|
||||
func PutContents(filePath string, data any, fileFlag ...int) (int, error)
|
||||
func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error
|
||||
func WriteOSFile(f *os.File, data any) (n int, err error)
|
||||
@@ -820,27 +813,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### Go Info
|
||||
|
||||
> Package `github.com/gookit/goutil/goinfo`
|
||||
|
||||
```go
|
||||
// source at goinfo/gofunc.go
|
||||
func FuncName(fn any) string
|
||||
func CutFuncName(fullFcName string) (pkgPath, shortFnName string)
|
||||
func PkgName(fullFcName string) string
|
||||
func GoodFuncName(name string) bool
|
||||
// source at goinfo/goinfo.go
|
||||
func GoVersion() string
|
||||
func ParseGoVersion(line string) (*GoInfo, error)
|
||||
func OsGoInfo() (*GoInfo, error)
|
||||
// source at goinfo/stack.go
|
||||
func GetCallStacks(all bool) []byte
|
||||
func GetCallerInfo(skip int) string
|
||||
func SimpleCallersInfo(skip, num int) []string
|
||||
func GetCallersInfo(skip, max int) []string
|
||||
```
|
||||
|
||||
### JSON Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/jsonutil`
|
||||
@@ -856,6 +828,7 @@ func EncodeUnescapeHTML(v any) ([]byte, error)
|
||||
func Decode(bts []byte, ptr any) error
|
||||
func DecodeString(str string, ptr any) error
|
||||
func DecodeReader(r io.Reader, ptr any) error
|
||||
func DecodeFile(file string, ptr any) error
|
||||
// source at jsonutil/jsonutil.go
|
||||
func WriteFile(filePath string, data any) error
|
||||
func WritePretty(filePath string, data any) error
|
||||
@@ -881,9 +854,14 @@ func HasOneKey(mp any, keys ...any) (ok bool, key any)
|
||||
func HasAllKeys(mp any, keys ...any) (ok bool, noKey any)
|
||||
// source at maputil/convert.go
|
||||
func KeyToLower(src map[string]string) map[string]string
|
||||
func AnyToStrMap(src any) map[string]string
|
||||
func ToStringMap(src map[string]any) map[string]string
|
||||
func ToL2StringMap(groupsMap map[string]any) map[string]map[string]string
|
||||
func CombineToSMap(keys, values []string) SMap
|
||||
func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V
|
||||
func SliceToSMap(kvPairs ...string) map[string]string
|
||||
func SliceToMap(kvPairs ...any) map[string]any
|
||||
func SliceToTypeMap[T any](valFunc func(any) T, kvPairs ...any) map[string]T
|
||||
func ToAnyMap(mp any) map[string]any
|
||||
func TryAnyMap(mp any) (map[string]any, error)
|
||||
func HTTPQueryString(data map[string]any) string
|
||||
@@ -902,14 +880,21 @@ func GetFromAny(path string, data any) (val any, ok bool)
|
||||
func GetByPath(path string, mp map[string]any) (val any, ok bool)
|
||||
func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool)
|
||||
func Keys(mp any) (keys []string)
|
||||
func TypedKeys[K comdef.SimpleType, V any](mp map[K]V) (keys []K)
|
||||
func FirstKey[T any](mp map[string]T) string
|
||||
func Values(mp any) (values []any)
|
||||
func TypedValues[K comdef.SimpleType, V any](mp map[K]V) (values []V)
|
||||
func EachAnyMap(mp any, fn func(key string, val any))
|
||||
func EachTypedMap[K comdef.SimpleType, V any](mp map[K]V, fn func(key K, val V))
|
||||
// source at maputil/maputil.go
|
||||
func SimpleMerge(src, dst map[string]any) map[string]any
|
||||
func Merge1level(mps ...map[string]any) map[string]any
|
||||
func DeepMerge(src, dst map[string]any, deep int) map[string]any
|
||||
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeStrMap(src, dst map[string]string) map[string]string
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeMultiSMap(mps ...map[string]string) map[string]string
|
||||
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string
|
||||
func FilterSMap(sm map[string]string) map[string]string
|
||||
func MakeByPath(path string, val any) (mp map[string]any)
|
||||
func MakeByKeys(keys []string, val any) (mp map[string]any)
|
||||
@@ -923,21 +908,23 @@ func SetByKeys(mp *map[string]any, keys []string, val any) (err error)
|
||||
> Package `github.com/gookit/goutil/mathutil`
|
||||
|
||||
```go
|
||||
// source at mathutil/calc.go
|
||||
func Abs[T comdef.Int](val T) T
|
||||
// source at mathutil/check.go
|
||||
func IsNumeric(c byte) bool
|
||||
func Compare(first, second any, op string) bool
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool)
|
||||
func CompInt64(first, second int64, op string) bool
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool)
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool)
|
||||
func InRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func OutRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func CompValue[T comdef.Number](first, second T, op string) (ok bool)
|
||||
func InRange[T comdef.Number](val, min, max T) bool
|
||||
func OutRange[T comdef.Number](val, min, max T) bool
|
||||
func InUintRange[T comdef.Uint](val, min, max T) bool
|
||||
// source at mathutil/compare.go
|
||||
func Min[T comdef.XintOrFloat](x, y T) T
|
||||
func Max[T comdef.XintOrFloat](x, y T) T
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func Min[T comdef.Number](x, y T) T
|
||||
func Max[T comdef.Number](x, y T) T
|
||||
func SwapMin[T comdef.Number](x, y T) (T, T)
|
||||
func SwapMax[T comdef.Number](x, y T) (T, T)
|
||||
func MaxInt(x, y int) int
|
||||
func SwapMaxInt(x, y int) (int, int)
|
||||
func MaxI64(x, y int64) int64
|
||||
@@ -1012,15 +999,15 @@ func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
|
||||
func DataSize(size uint64) string
|
||||
func HowLongAgo(sec int64) string
|
||||
// source at mathutil/mathutil.go
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
|
||||
func OrElse[T comdef.Number](val, defVal T) T
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T
|
||||
func LessOr[T comdef.Number](val, max, devVal T) T
|
||||
func LteOr[T comdef.Number](val, max, devVal T) T
|
||||
func GreaterOr[T comdef.Number](val, min, defVal T) T
|
||||
func GteOr[T comdef.Number](val, min, defVal T) T
|
||||
func Mul[T1, T2 comdef.Number](a T1, b T2) float64
|
||||
func MulF2i(a, b float64) int
|
||||
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
|
||||
func Div[T1, T2 comdef.Number](a T1, b T2) float64
|
||||
func DivInt[T comdef.Integer](a, b T) int
|
||||
func DivF2i(a, b float64) int
|
||||
func Percent(val, total int) float64
|
||||
@@ -1029,8 +1016,6 @@ func RandomInt(min, max int) int
|
||||
func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
// source at mathutil/value.go
|
||||
func New[T comdef.IntOrFloat](v T) *Num[T]
|
||||
```
|
||||
|
||||
### Reflects
|
||||
@@ -1039,6 +1024,8 @@ func New[T comdef.IntOrFloat](v T) *Num[T]
|
||||
|
||||
```go
|
||||
// source at reflects/check.go
|
||||
func IsTimeType(t reflect.Type) bool
|
||||
func IsDurationType(t reflect.Type) bool
|
||||
func HasChild(v reflect.Value) bool
|
||||
func IsArrayOrSlice(k reflect.Kind) bool
|
||||
func IsSimpleKind(k reflect.Kind) bool
|
||||
@@ -1047,6 +1034,7 @@ func IsIntLike(k reflect.Kind) bool
|
||||
func IsIntx(k reflect.Kind) bool
|
||||
func IsUintX(k reflect.Kind) bool
|
||||
func IsNil(v reflect.Value) bool
|
||||
func IsValidPtr(v reflect.Value) bool
|
||||
func CanBeNil(typ reflect.Type) bool
|
||||
func IsFunc(val any) bool
|
||||
func IsEqual(src, dst any) bool
|
||||
@@ -1057,12 +1045,13 @@ func BaseTypeVal(v reflect.Value) (value any, err error)
|
||||
func ToBaseVal(v reflect.Value) (value any, err error)
|
||||
func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error)
|
||||
func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error)
|
||||
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error)
|
||||
func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error)
|
||||
func ValueByKind(val any, kind reflect.Kind) (reflect.Value, error)
|
||||
func ConvToKind(val any, kind reflect.Kind, fallback ...ConvFunc) (rv reflect.Value, err error)
|
||||
func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error)
|
||||
func String(rv reflect.Value) string
|
||||
func ToString(rv reflect.Value) (str string, err error)
|
||||
func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error)
|
||||
func ToTimeOrDuration(str string, typ reflect.Type) (any, error)
|
||||
// source at reflects/func.go
|
||||
func NewFunc(fn any) *FuncX
|
||||
func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error)
|
||||
@@ -1070,8 +1059,9 @@ func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value
|
||||
func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error)
|
||||
func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error)
|
||||
// source at reflects/map.go
|
||||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value))
|
||||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any))
|
||||
func TryAnyMap(mp reflect.Value) (map[string]any, error)
|
||||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) (err error)
|
||||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) error
|
||||
func FlatMap(rv reflect.Value, fn FlatFunc)
|
||||
// source at reflects/slice.go
|
||||
func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value
|
||||
@@ -1098,32 +1088,6 @@ func Wrap(rv reflect.Value) Value
|
||||
func ValueOf(v any) Value
|
||||
```
|
||||
|
||||
### Stdio
|
||||
|
||||
> Package `github.com/gookit/goutil/stdio`
|
||||
|
||||
```go
|
||||
// source at stdio/ioutil.go
|
||||
func QuietFprint(w io.Writer, a ...any)
|
||||
func QuietFprintf(w io.Writer, tpl string, vs ...any)
|
||||
func QuietFprintln(w io.Writer, a ...any)
|
||||
func QuietWriteString(w io.Writer, ss ...string)
|
||||
// source at stdio/stdio.go
|
||||
func DiscardReader(src io.Reader)
|
||||
func ReadString(r io.Reader) string
|
||||
func MustReadReader(r io.Reader) []byte
|
||||
func NewIOReader(in any) io.Reader
|
||||
func NewScanner(in any) *bufio.Scanner
|
||||
func WriteByte(b byte)
|
||||
func WriteBytes(bs []byte)
|
||||
func WritelnBytes(bs []byte)
|
||||
func WriteString(s string)
|
||||
func Writeln(s string)
|
||||
// source at stdio/writer.go
|
||||
func WrapW(w io.Writer) *WriteWrapper
|
||||
func NewWriteWrapper(w io.Writer) *WriteWrapper
|
||||
```
|
||||
|
||||
### Structs
|
||||
|
||||
> Package `github.com/gookit/goutil/structs`
|
||||
@@ -1140,8 +1104,10 @@ func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error)
|
||||
func MustToSMap(st any, optFns ...MapOptFunc) map[string]string
|
||||
func ToString(st any, optFns ...MapOptFunc) string
|
||||
func WithMapTagName(tagName string) MapOptFunc
|
||||
func WithUserFunc(fn CustomUserFunc) MapOptFunc
|
||||
func MergeAnonymous(opt *MapOptions)
|
||||
func ExportPrivate(opt *MapOptions)
|
||||
func WithIgnoreEmpty(opt *MapOptions)
|
||||
func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error)
|
||||
// source at structs/copy.go
|
||||
func MapStruct(srcSt, dstSt any)
|
||||
@@ -1172,6 +1138,8 @@ func WrapValue(rv reflect.Value) *Wrapper
|
||||
// source at structs/writer.go
|
||||
func NewWriter(ptr any) *Wrapper
|
||||
func WithParseDefault(opt *SetOptions)
|
||||
func WithBeforeSetFn(fn BeforeSetFunc) SetOptFunc
|
||||
func BindData(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
```
|
||||
|
||||
@@ -1181,10 +1149,12 @@ func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
|
||||
```go
|
||||
// source at strutil/bytes.go
|
||||
func NewBuffer() *Buffer
|
||||
func NewBuffer(initSize ...int) *Buffer
|
||||
func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool
|
||||
// source at strutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsInt(s string) bool
|
||||
func IsFloat(s string) bool
|
||||
func IsNumeric(s string) bool
|
||||
func IsAlphabet(char uint8) bool
|
||||
func IsAlphaNum(c uint8) bool
|
||||
@@ -1196,8 +1166,10 @@ func IContains(s, sub string) bool
|
||||
func ContainsByte(s string, c byte) bool
|
||||
func ContainsOne(s string, subs []string) bool
|
||||
func HasOneSub(s string, subs []string) bool
|
||||
func IContainsOne(s string, subs []string) bool
|
||||
func ContainsAll(s string, subs []string) bool
|
||||
func HasAllSubs(s string, subs []string) bool
|
||||
func IContainsAll(s string, subs []string) bool
|
||||
func IsStartsOf(s string, prefixes []string) bool
|
||||
func HasOnePrefix(s string, prefixes []string) bool
|
||||
func HasPrefix(s string, prefix string) bool
|
||||
@@ -1215,6 +1187,7 @@ func IsSymbol(r rune) bool
|
||||
func HasEmpty(ss ...string) bool
|
||||
func IsAllEmpty(ss ...string) bool
|
||||
func IsVersion(s string) bool
|
||||
func IsVarName(s string) bool
|
||||
func Compare(s1, s2, op string) bool
|
||||
func VersionCompare(v1, v2, op string) bool
|
||||
func SimpleMatch(s string, keywords []string) bool
|
||||
@@ -1232,6 +1205,7 @@ func Quote(s string) string
|
||||
func Unquote(s string) string
|
||||
func Join(sep string, ss ...string) string
|
||||
func JoinList(sep string, ss []string) string
|
||||
func JoinComma(ss []string) string
|
||||
func JoinAny(sep string, parts ...any) string
|
||||
func Implode(sep string, ss ...string) string
|
||||
func String(val any) (string, error)
|
||||
@@ -1331,6 +1305,7 @@ func IndentBytes(b, prefix []byte) []byte
|
||||
func MicroTimeID() string
|
||||
func MicroTimeHexID() string
|
||||
func MTimeHexID() string
|
||||
func MTimeBase36() string
|
||||
func MTimeBaseID(toBase int) string
|
||||
func DatetimeNo(prefix string) string
|
||||
func DateSN(prefix string) string
|
||||
@@ -1339,6 +1314,8 @@ func DateSNV2(prefix string, extBase ...int) string
|
||||
func Md5(src any) string
|
||||
func MD5(src any) string
|
||||
func GenMd5(src any) string
|
||||
func Md5Simple(src any) string
|
||||
func Md5Base62(src any) string
|
||||
func Md5Bytes(src any) []byte
|
||||
func ShortMd5(src any) string
|
||||
func HashPasswd(pwd, key string) string
|
||||
@@ -1388,6 +1365,7 @@ func RunesWidth(rs []rune) (w int)
|
||||
func Truncate(s string, w int, tail string) string
|
||||
func TextTruncate(s string, w int, tail string) string
|
||||
func Utf8Truncate(s string, w int, tail string) string
|
||||
func Chunk[T ~string](s T, size int) []T
|
||||
func TextSplit(s string, w int) []string
|
||||
func Utf8Split(s string, w int) []string
|
||||
func TextWrap(s string, w int) string
|
||||
@@ -1409,6 +1387,7 @@ func SplitNValid(s, sep string, n int) (ss []string)
|
||||
func SplitN(s, sep string, n int) (ss []string)
|
||||
func SplitTrimmed(s, sep string) (ss []string)
|
||||
func SplitNTrimmed(s, sep string, n int) (ss []string)
|
||||
func SplitByWhitespace(s string) []string
|
||||
func Substr(s string, pos, length int) string
|
||||
func SplitInlineComment(val string, strict ...bool) (string, string)
|
||||
func FirstLine(output string) string
|
||||
@@ -1433,12 +1412,12 @@ func SubstrCount(s, substr string, params ...uint64) (int, error)
|
||||
|
||||
```go
|
||||
// source at syncs/chan.go
|
||||
func WaitCloseSignals(onClose func(sig os.Signal))
|
||||
func Go(f func() error) error
|
||||
// source at syncs/group.go
|
||||
func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context)
|
||||
func NewErrGroup(limit ...int) *ErrGroup
|
||||
// source at syncs/signal.go
|
||||
func WaitCloseSignals(onClose func(sig os.Signal), sigCh ...chan os.Signal)
|
||||
func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error))
|
||||
```
|
||||
|
||||
@@ -1454,15 +1433,14 @@ func QuickExec(cmdLine string, workDir ...string) (string, error)
|
||||
func ExecLine(cmdLine string, workDir ...string) (string, error)
|
||||
func ExecCmd(binName string, args []string, workDir ...string) (string, error)
|
||||
func ShellExec(cmdLine string, shells ...string) (string, error)
|
||||
// source at sysutil/stack.go
|
||||
func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo
|
||||
// source at sysutil/sysenv.go
|
||||
func IsMSys() bool
|
||||
func IsWSL() bool
|
||||
func IsConsole(out io.Writer) bool
|
||||
func IsTerminal(fd uintptr) bool
|
||||
func StdIsTerminal() bool
|
||||
func Hostname() string
|
||||
func CurrentShell(onlyName bool) (path string)
|
||||
func CurrentShell(onlyName bool, fallbackShell ...string) string
|
||||
func HasShellEnv(shell string) bool
|
||||
func IsShellSpecialVar(c uint8) bool
|
||||
func FindExecutable(binName string) (string, error)
|
||||
@@ -1472,11 +1450,13 @@ func Getenv(name string, def ...string) string
|
||||
func Environ() map[string]string
|
||||
func EnvMapWith(newEnv map[string]string) map[string]string
|
||||
func EnvPaths() []string
|
||||
func SearchPath(keywords string, limit int) []string
|
||||
func ToEnvPATH(paths []string) string
|
||||
func SearchPath(keywords string, limit int, opts ...SearchPathOption) []string
|
||||
// source at sysutil/sysgo.go
|
||||
func GoVersion() string
|
||||
func ParseGoVersion(line string) (*GoInfo, error)
|
||||
func OsGoInfo() (*GoInfo, error)
|
||||
func CallersInfos(skip, num int, filters ...goinfo.CallerFilterFunc) []*CallerInfo
|
||||
// source at sysutil/sysutil.go
|
||||
func Workdir() string
|
||||
func BinDir() string
|
||||
@@ -1485,16 +1465,16 @@ func BinFile() string
|
||||
func Open(fileOrURL string) error
|
||||
func OpenBrowser(fileOrURL string) error
|
||||
func OpenFile(path string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
func Kill(pid int, signal syscall.Signal) error
|
||||
func ProcessExists(pid int) bool
|
||||
// source at sysutil/sysutil_unix.go
|
||||
// source at sysutil/sysutil_linux.go
|
||||
func IsWin() bool
|
||||
func IsWindows() bool
|
||||
func IsMac() bool
|
||||
func IsDarwin() bool
|
||||
func IsLinux() bool
|
||||
func OpenURL(URL string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
func Kill(pid int, signal syscall.Signal) error
|
||||
func ProcessExists(pid int) bool
|
||||
// source at sysutil/user.go
|
||||
func MustFindUser(uname string) *user.User
|
||||
func LoginUser() *user.User
|
||||
@@ -1502,12 +1482,13 @@ func CurrentUser() *user.User
|
||||
func UHomeDir() string
|
||||
func UserHomeDir() string
|
||||
func HomeDir() string
|
||||
func UserDir(subPath string) string
|
||||
func UserCacheDir(subPath string) string
|
||||
func UserConfigDir(subPath string) string
|
||||
func UserDir(subPaths ...string) string
|
||||
func UserCacheDir(subPaths ...string) string
|
||||
func UserConfigDir(subPaths ...string) string
|
||||
func ExpandPath(path string) string
|
||||
func ExpandHome(path string) string
|
||||
// source at sysutil/user_nonwin.go
|
||||
func IsAdmin() bool
|
||||
func ChangeUserByName(newUname string) error
|
||||
func ChangeUserUidGid(newUID int, newGid int) error
|
||||
func ChangeUserUIDGid(newUID int, newGid int) (err error)
|
||||
@@ -1525,15 +1506,18 @@ func MockEnvValue(key, val string, fn func(nv string))
|
||||
func MockEnvValues(kvMap map[string]string, fn func())
|
||||
func MockOsEnvByText(envText string, fn func())
|
||||
func MockOsEnv(mp map[string]string, fn func())
|
||||
func SetOsEnvs(mp map[string]string) string
|
||||
func RemoveTmpEnvs(tmpKey string)
|
||||
func ClearOSEnv()
|
||||
func RevertOSEnv()
|
||||
func RunOnCleanEnv(runFn func())
|
||||
func MockCleanOsEnv(mp map[string]string, fn func())
|
||||
// source at testutil/httpmock.go
|
||||
func NewHttpRequest(method, path string, data *MD) *http.Request
|
||||
func NewHTTPRequest(method, path string, data *MD) *http.Request
|
||||
func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder
|
||||
func MockHttpServer() *EchoServer
|
||||
func TestMain(m *testing.M)
|
||||
func NewEchoServer() *httptest.Server
|
||||
func NewEchoServer() *EchoServer
|
||||
func BuildEchoReply(r *http.Request) *EchoReply
|
||||
func ParseRespToReply(w *http.Response) *EchoReply
|
||||
func ParseBodyToReply(bd io.ReadCloser) *EchoReply
|
||||
@@ -1549,7 +1533,7 @@ func SetTimeLocalUTC()
|
||||
func RestoreTimeLocal()
|
||||
// source at testutil/writer.go
|
||||
func NewTestWriter() *TestWriter
|
||||
func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry
|
||||
func NewDirEnt(fPath string, isDir ...bool) *fakeobj.DirEntry
|
||||
```
|
||||
|
||||
### Timex
|
||||
@@ -1749,13 +1733,6 @@ go test -v -run ^TestErr$
|
||||
go test -v -run ^TestErr$ ./testutil/assert/...
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- https://github.com/duke-git/lancet
|
||||
- https://github.com/samber/lo
|
||||
- https://github.com/zyedidia/generic
|
||||
- https://github.com/thoas/go-funk
|
||||
|
||||
## Gookit packages
|
||||
|
||||
- [gookit/ini](https://github.com/gookit/ini) Go config management, use INI files
|
||||
@@ -1771,6 +1748,13 @@ go test -v -run ^TestErr$ ./testutil/assert/...
|
||||
- [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
|
||||
|
||||
## Related
|
||||
|
||||
- https://github.com/duke-git/lancet
|
||||
- https://github.com/samber/lo
|
||||
- https://github.com/zyedidia/generic
|
||||
- https://github.com/thoas/go-funk
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
50
vendor/github.com/gookit/goutil/arrutil/README.zh-CN.md
generated
vendored
Normal file
50
vendor/github.com/gookit/goutil/arrutil/README.zh-CN.md
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
## ArrUtil
|
||||
|
||||
`arrutil` 是一个用于操作数组和切片的工具包,提供了丰富的功能来简化 Go 语言中数组和切片的处理。
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
go get github.com/gookit/goutil/arrutil
|
||||
```
|
||||
|
||||
## Go docs
|
||||
|
||||
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/arrutil)
|
||||
|
||||
## 基本功能
|
||||
|
||||
主要包括以下功能:
|
||||
|
||||
1. **数组/切片的基本操作**:
|
||||
- `RandomOne`:从数组或切片中随机获取一个元素。
|
||||
- `Reverse`:反转数组或切片中的元素顺序。
|
||||
|
||||
2. **检查和查找**:
|
||||
- `Contains` 和 `HasValue`:检查数组或切片是否包含特定值。
|
||||
- `InStrings` 和 `StringsHas`:检查字符串切片中是否包含特定字符串。
|
||||
- `IntsHas` 和 `Int64sHas`:检查整数切片中是否包含特定整数值。
|
||||
- `Find` 和 `FindOrDefault`:根据谓词函数查找元素,如果没有找到则返回默认值。
|
||||
|
||||
3. **集合操作**:
|
||||
- `Union`:计算两个切片的并集。
|
||||
- `Intersects`:计算两个切片的交集。
|
||||
- `Excepts` 和 `Differences`:计算两个切片的差集。
|
||||
- `TwowaySearch`:在切片中双向搜索特定元素。
|
||||
|
||||
4. **转换和格式化**:
|
||||
- `ToInt64s` 和 `ToStrings`:将任意类型的切片转换为整数或字符串切片。
|
||||
- `JoinSlice` 和 `JoinStrings`:将切片中的元素连接成一个字符串。
|
||||
- `FormatIndent`:将数组或切片格式化为带有缩进的字符串。
|
||||
|
||||
5. **排序和过滤**:
|
||||
- `Sort`:对切片进行排序。
|
||||
- `Filter`:根据条件过滤切片中的元素。
|
||||
- `Remove`:从切片中移除特定元素。
|
||||
|
||||
6. **其他实用功能**:
|
||||
- `Unique`:去除切片中的重复元素。
|
||||
- `FirstOr`:获取切片的第一个元素,如果切片为空则返回默认值。
|
||||
|
||||
这些功能使得在 Go 语言中处理数组和切片变得更加方便和高效。无论是进行数据处理、集合运算还是字符串操作,`arrutil` 都提供了一系列简洁且易于使用的函数来帮助开发者完成任务。
|
||||
|
||||
30
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
30
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
@@ -126,7 +126,7 @@ func SliceToInt64s(arr []any) []int64 {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert func for anys
|
||||
* convert func for any-slice
|
||||
*************************************************************/
|
||||
|
||||
// AnyToSlice convert any(allow: array,slice) to []any
|
||||
@@ -159,22 +159,28 @@ func MustToStrings(arr any) []string {
|
||||
|
||||
// ToStrings convert any(allow: array,slice) to []string
|
||||
func ToStrings(arr any) (ret []string, err error) {
|
||||
rv := reflect.ValueOf(arr)
|
||||
if rv.Kind() == reflect.String {
|
||||
return []string{rv.String()}, nil
|
||||
// try direct convert
|
||||
switch typVal := arr.(type) {
|
||||
case string:
|
||||
return []string{typVal}, nil
|
||||
case []string:
|
||||
return typVal, nil
|
||||
case []any:
|
||||
return SliceToStrings(typVal), nil
|
||||
}
|
||||
|
||||
// try use reflect to convert
|
||||
rv := reflect.ValueOf(arr)
|
||||
if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array {
|
||||
err = ErrInvalidType
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
str, err := strutil.ToString(rv.Index(i).Interface())
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
str, err1 := strutil.ToString(rv.Index(i).Interface())
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
|
||||
ret = append(ret, str)
|
||||
}
|
||||
return
|
||||
@@ -182,11 +188,6 @@ func ToStrings(arr any) (ret []string, err error) {
|
||||
|
||||
// SliceToStrings safe convert []any to []string
|
||||
func SliceToStrings(arr []any) []string {
|
||||
return QuietStrings(arr)
|
||||
}
|
||||
|
||||
// QuietStrings safe convert []any to []string
|
||||
func QuietStrings(arr []any) []string {
|
||||
ss := make([]string, len(arr))
|
||||
for i, v := range arr {
|
||||
ss[i] = strutil.SafeString(v)
|
||||
@@ -194,6 +195,9 @@ func QuietStrings(arr []any) []string {
|
||||
return ss
|
||||
}
|
||||
|
||||
// QuietStrings safe convert []any to []string
|
||||
func QuietStrings(arr []any) []string { return SliceToStrings(arr) }
|
||||
|
||||
// ConvType convert type of slice elements to new type slice, by the given newElemTyp type.
|
||||
//
|
||||
// Supports conversion between []string, []intX, []uintX, []floatX.
|
||||
|
||||
17
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
17
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
@@ -74,7 +74,7 @@ func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
|
||||
}
|
||||
|
||||
// Unique value in the given slice data.
|
||||
func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
|
||||
func Unique[T comdef.NumberOrString](list []T) []T {
|
||||
if len(list) < 2 {
|
||||
return list
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
|
||||
}
|
||||
|
||||
// IndexOf value in given slice.
|
||||
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
|
||||
func IndexOf[T comdef.NumberOrString](val T, list []T) int {
|
||||
for i, v := range list {
|
||||
if v == val {
|
||||
return i
|
||||
@@ -100,3 +100,16 @@ func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// FirstOr get first value of slice, if slice is empty, return the default value.
|
||||
func FirstOr[T any](list []T, defVal ...T) T {
|
||||
if len(list) > 0 {
|
||||
return list[0]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
4
vendor/github.com/gookit/goutil/arrutil/strings.go
generated
vendored
4
vendor/github.com/gookit/goutil/arrutil/strings.go
generated
vendored
@@ -47,6 +47,10 @@ func StringsTryInts(ss []string) (ints []int, err error) {
|
||||
|
||||
// StringsUnique unique string slice
|
||||
func StringsUnique(ss []string) []string {
|
||||
if len(ss) == 0 {
|
||||
return ss
|
||||
}
|
||||
|
||||
var unique []string
|
||||
for _, s := range ss {
|
||||
if !StringsContains(unique, s) {
|
||||
|
||||
2
vendor/github.com/gookit/goutil/byteutil/README.md
generated
vendored
2
vendor/github.com/gookit/goutil/byteutil/README.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
# Bytes Util
|
||||
|
||||
Provide some commonly bytes util functions.
|
||||
Provide some common bytes util functions.
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
19
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
19
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
@@ -13,6 +13,14 @@ import (
|
||||
|
||||
// Md5 Generate a 32-bit md5 bytes
|
||||
func Md5(src any) []byte {
|
||||
bs := Md5Sum(src)
|
||||
dst := make([]byte, hex.EncodedLen(len(bs)))
|
||||
hex.Encode(dst, bs)
|
||||
return dst
|
||||
}
|
||||
|
||||
// Md5Sum Generate a md5 bytes
|
||||
func Md5Sum(src any) []byte {
|
||||
h := md5.New()
|
||||
|
||||
switch val := src.(type) {
|
||||
@@ -24,16 +32,11 @@ func Md5(src any) []byte {
|
||||
h.Write([]byte(fmt.Sprint(src)))
|
||||
}
|
||||
|
||||
bs := h.Sum(nil) // cap(bs) == 16
|
||||
dst := make([]byte, hex.EncodedLen(len(bs)))
|
||||
hex.Encode(dst, bs)
|
||||
return dst
|
||||
return h.Sum(nil) // cap(bs) == 16
|
||||
}
|
||||
|
||||
// ShortMd5 Generate a 16-bit md5 bytes. remove first 8 and last 8 bytes from 32-bit md5.
|
||||
func ShortMd5(src any) []byte {
|
||||
return Md5(src)[8:24]
|
||||
}
|
||||
// ShortMd5 Generate a 16-bit md5 bytes. remove the first 8 and last 8 bytes from 32-bit md5.
|
||||
func ShortMd5(src any) []byte { return Md5(src)[8:24] }
|
||||
|
||||
// Random bytes generate
|
||||
func Random(length int) ([]byte, error) {
|
||||
|
||||
6
vendor/github.com/gookit/goutil/byteutil/check.go
generated
vendored
6
vendor/github.com/gookit/goutil/byteutil/check.go
generated
vendored
@@ -2,3 +2,9 @@ package byteutil
|
||||
|
||||
// IsNumChar returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumChar(c byte) bool { return c >= '0' && c <= '9' }
|
||||
|
||||
// IsAlphaChar returns true if the given character is a alphabet, otherwise false.
|
||||
func IsAlphaChar(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
|
||||
86
vendor/github.com/gookit/goutil/check.go
generated
vendored
86
vendor/github.com/gookit/goutil/check.go
generated
vendored
@@ -1,86 +0,0 @@
|
||||
package goutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
)
|
||||
|
||||
// IsNil value check
|
||||
func IsNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsNil(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsZero value check, alias of the IsEmpty()
|
||||
var IsZero = IsEmpty
|
||||
|
||||
// IsEmpty value check
|
||||
func IsEmpty(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsEmpty(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// Alias of the IsEmptyReal()
|
||||
var IsZeroReal = IsEmptyReal
|
||||
|
||||
// IsEmptyReal checks for empty given value and also real empty value if the passed value is a pointer
|
||||
func IsEmptyReal(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsEmptyReal(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsFunc value
|
||||
func IsFunc(val any) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
return reflect.TypeOf(val).Kind() == reflect.Func
|
||||
}
|
||||
|
||||
// IsEqual determines if two objects are considered equal.
|
||||
//
|
||||
// TIP: cannot compare function type
|
||||
func IsEqual(src, dst any) bool {
|
||||
if src == nil || dst == nil {
|
||||
return src == dst
|
||||
}
|
||||
|
||||
// cannot compare function type
|
||||
if IsFunc(src) || IsFunc(dst) {
|
||||
return false
|
||||
}
|
||||
return reflects.IsEqual(src, dst)
|
||||
}
|
||||
|
||||
// Contains try loop over the data check if the data includes the element.
|
||||
// alias of the IsContains
|
||||
//
|
||||
// TIP: only support types: string, map, array, slice
|
||||
//
|
||||
// map - check key exists
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func Contains(data, elem any) bool {
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
|
||||
// IsContains try loop over the data check if the data includes the element.
|
||||
//
|
||||
// TIP: only support types: string, map, array, slice
|
||||
//
|
||||
// map - check key exists
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func IsContains(data, elem any) bool {
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
34
vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go
generated
vendored
34
vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go
generated
vendored
@@ -3,6 +3,7 @@ package cmdline
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
@@ -24,6 +25,12 @@ func NewBuilder(binFile string, args ...string) *LineBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// ResetGet value, will reset after get.
|
||||
func (b *LineBuilder) ResetGet() string {
|
||||
defer b.Reset()
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// AddArg to builder
|
||||
func (b *LineBuilder) AddArg(arg string) {
|
||||
_, _ = b.WriteString(arg)
|
||||
@@ -51,35 +58,10 @@ func (b *LineBuilder) AddAny(args ...any) {
|
||||
// WriteString arg string to the builder, will auto quote special string.
|
||||
// refer strconv.Quote()
|
||||
func (b *LineBuilder) WriteString(a string) (int, error) {
|
||||
var quote byte
|
||||
if pos := strings.IndexByte(a, '"'); pos > -1 {
|
||||
quote = '\''
|
||||
// fix: a = `--pretty=format:"one two three"`
|
||||
if pos > 0 && a[len(a)-1] == '"' {
|
||||
quote = 0
|
||||
}
|
||||
} else if pos := strings.IndexByte(a, '\''); pos > -1 {
|
||||
quote = '"'
|
||||
// fix: a = "--pretty=format:'one two three'"
|
||||
if pos > 0 && a[len(a)-1] == '\'' {
|
||||
quote = 0
|
||||
}
|
||||
} else if a == "" || strings.ContainsRune(a, ' ') {
|
||||
quote = '"'
|
||||
}
|
||||
|
||||
// add sep on not-first write.
|
||||
if b.Len() != 0 {
|
||||
_ = b.WriteByte(' ')
|
||||
}
|
||||
|
||||
// no quote char OR not need quote
|
||||
if quote == 0 {
|
||||
return b.Builder.WriteString(a)
|
||||
}
|
||||
|
||||
_ = b.WriteByte(quote) // add start quote
|
||||
n, err := b.Builder.WriteString(a)
|
||||
_ = b.WriteByte(quote) // add end quote
|
||||
return n, err
|
||||
return b.Builder.WriteString(comfunc.ShellQuote(a))
|
||||
}
|
||||
|
||||
9
vendor/github.com/gookit/goutil/cliutil/cmdline/cmdline.go
generated
vendored
9
vendor/github.com/gookit/goutil/cliutil/cmdline/cmdline.go
generated
vendored
@@ -1,12 +1,15 @@
|
||||
// Package cmdline provide quick build and parse cmd line string.
|
||||
package cmdline
|
||||
|
||||
import "github.com/gookit/goutil/internal/comfunc"
|
||||
|
||||
// LineBuild build command line string by given args.
|
||||
func LineBuild(binFile string, args []string) string {
|
||||
return NewBuilder(binFile, args...).String()
|
||||
}
|
||||
|
||||
// ParseLine input command line text. alias of the StringToOSArgs()
|
||||
func ParseLine(line string) []string {
|
||||
return NewParser(line).Parse()
|
||||
}
|
||||
func ParseLine(line string) []string { return NewParser(line).Parse() }
|
||||
|
||||
// Quote string in shell command env
|
||||
func Quote(s string) string { return comfunc.ShellQuote(s) }
|
||||
|
||||
8
vendor/github.com/gookit/goutil/comdef/comdef.go
generated
vendored
8
vendor/github.com/gookit/goutil/comdef/comdef.go
generated
vendored
@@ -1,14 +1,6 @@
|
||||
// Package comdef provide some common type or constant definitions
|
||||
package comdef
|
||||
|
||||
type (
|
||||
// MarshalFunc define
|
||||
MarshalFunc func(v any) ([]byte, error)
|
||||
|
||||
// UnmarshalFunc define
|
||||
UnmarshalFunc func(bts []byte, ptr any) error
|
||||
)
|
||||
|
||||
// ToTypeFunc convert value to defined type
|
||||
type ToTypeFunc[T any] func(any) (T, error)
|
||||
|
||||
|
||||
12
vendor/github.com/gookit/goutil/comdef/formatter.go
generated
vendored
12
vendor/github.com/gookit/goutil/comdef/formatter.go
generated
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/gookit/goutil/stdio"
|
||||
"github.com/gookit/goutil/x/stdio"
|
||||
)
|
||||
|
||||
// DataFormatter interface
|
||||
@@ -14,6 +14,13 @@ type DataFormatter interface {
|
||||
}
|
||||
|
||||
// BaseFormatter struct
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// type YourFormatter struct {
|
||||
// comdef.BaseFormatter
|
||||
// }
|
||||
// // implement the DataFormatter interface...
|
||||
type BaseFormatter struct {
|
||||
ow ByteStringWriter
|
||||
// Out formatted to the writer
|
||||
@@ -41,7 +48,7 @@ func (f *BaseFormatter) SetOutput(out io.Writer) {
|
||||
f.Out = out
|
||||
}
|
||||
|
||||
// BsWriter build and get
|
||||
// BsWriter warp the Out, build a ByteStringWriter
|
||||
func (f *BaseFormatter) BsWriter() ByteStringWriter {
|
||||
if f.ow == nil {
|
||||
if f.Out == nil {
|
||||
@@ -52,6 +59,5 @@ func (f *BaseFormatter) BsWriter() ByteStringWriter {
|
||||
f.ow = stdio.NewWriteWrapper(f.Out)
|
||||
}
|
||||
}
|
||||
|
||||
return f.ow
|
||||
}
|
||||
|
||||
3
vendor/github.com/gookit/goutil/comdef/interface.go
generated
vendored
3
vendor/github.com/gookit/goutil/comdef/interface.go
generated
vendored
@@ -29,6 +29,9 @@ type Float64able interface {
|
||||
Float64() (float64, error)
|
||||
}
|
||||
|
||||
// MapFunc definition
|
||||
type MapFunc func(val any) (any, error)
|
||||
|
||||
//
|
||||
//
|
||||
// Matcher type
|
||||
|
||||
27
vendor/github.com/gookit/goutil/comdef/serializer.go
generated
vendored
Normal file
27
vendor/github.com/gookit/goutil/comdef/serializer.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package comdef
|
||||
|
||||
type (
|
||||
// MarshalFunc define
|
||||
MarshalFunc func(v any) ([]byte, error)
|
||||
|
||||
// UnmarshalFunc define
|
||||
UnmarshalFunc func(bts []byte, ptr any) error
|
||||
)
|
||||
|
||||
// Serializer interface definition
|
||||
type Serializer interface {
|
||||
Serialize(v any) ([]byte, error)
|
||||
Deserialize(data []byte, v any) error
|
||||
}
|
||||
|
||||
// GoSerializer interface definition
|
||||
type GoSerializer interface {
|
||||
Marshal(v any) ([]byte, error)
|
||||
Unmarshal(v []byte, ptr any) error
|
||||
}
|
||||
|
||||
// Codec interface definition
|
||||
type Codec interface {
|
||||
Decode(blob []byte, v any) (err error)
|
||||
Encode(v any) (out []byte, err error)
|
||||
}
|
||||
25
vendor/github.com/gookit/goutil/comdef/types.go
generated
vendored
25
vendor/github.com/gookit/goutil/comdef/types.go
generated
vendored
@@ -25,16 +25,28 @@ type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
// IntOrFloat interface type. all int and float types
|
||||
// IntOrFloat interface type. all int and float types, but NOT uint types
|
||||
type IntOrFloat interface {
|
||||
Int | Float
|
||||
}
|
||||
|
||||
// XintOrFloat interface type. all int, uint and float types
|
||||
// Number interface type. contains all int, uint and float types
|
||||
type Number interface {
|
||||
Int | Uint | Float
|
||||
}
|
||||
|
||||
// XintOrFloat interface type. all int, uint and float types. alias of Number
|
||||
//
|
||||
// Deprecated: use Number instead.
|
||||
type XintOrFloat interface {
|
||||
Int | Uint | Float
|
||||
}
|
||||
|
||||
// NumberOrString interface type for (x)int, float, ~string types
|
||||
type NumberOrString interface {
|
||||
Int | Uint | Float | ~string
|
||||
}
|
||||
|
||||
// SortedType interface type. same of constraints.Ordered
|
||||
//
|
||||
// it can be ordered, that supports the operators < <= >= >.
|
||||
@@ -67,3 +79,12 @@ type SimpleType interface {
|
||||
type ScalarType interface {
|
||||
Int | Uint | Float | ~string | ~bool
|
||||
}
|
||||
|
||||
// StrMap is alias of map[string]string
|
||||
type StrMap map[string]string
|
||||
|
||||
// AnyMap is alias of map[string]any
|
||||
type AnyMap map[string]any
|
||||
|
||||
// L2StrMap is alias of map[string]map[string]string
|
||||
type L2StrMap map[string]map[string]string
|
||||
|
||||
32
vendor/github.com/gookit/goutil/conv.go
generated
vendored
32
vendor/github.com/gookit/goutil/conv.go
generated
vendored
@@ -20,20 +20,16 @@ func Bool(v any) bool {
|
||||
}
|
||||
|
||||
// ToBool try to convert type to bool
|
||||
func ToBool(v any) (bool, error) {
|
||||
return comfunc.ToBool(v)
|
||||
}
|
||||
func ToBool(v any) (bool, error) { return comfunc.ToBool(v) }
|
||||
|
||||
// String always convert value to string, will ignore error
|
||||
// String func. always converts value to string, will ignore error
|
||||
func String(v any) string {
|
||||
s, _ := strutil.AnyToString(v, false)
|
||||
return s
|
||||
}
|
||||
|
||||
// ToString convert value to string, will return error on fail.
|
||||
func ToString(v any) (string, error) {
|
||||
return strutil.AnyToString(v, true)
|
||||
}
|
||||
func ToString(v any) (string, error) { return strutil.AnyToString(v, true) }
|
||||
|
||||
// Int convert value to int
|
||||
func Int(v any) int {
|
||||
@@ -42,9 +38,7 @@ func Int(v any) int {
|
||||
}
|
||||
|
||||
// ToInt try to convert value to int
|
||||
func ToInt(v any) (int, error) {
|
||||
return mathutil.ToInt(v)
|
||||
}
|
||||
func ToInt(v any) (int, error) { return mathutil.ToInt(v) }
|
||||
|
||||
// Int64 convert value to int64
|
||||
func Int64(v any) int64 {
|
||||
@@ -53,9 +47,7 @@ func Int64(v any) int64 {
|
||||
}
|
||||
|
||||
// ToInt64 try to convert value to int64
|
||||
func ToInt64(v any) (int64, error) {
|
||||
return mathutil.ToInt64(v)
|
||||
}
|
||||
func ToInt64(v any) (int64, error) { return mathutil.ToInt64(v) }
|
||||
|
||||
// Uint convert value to uint
|
||||
func Uint(v any) uint {
|
||||
@@ -64,9 +56,7 @@ func Uint(v any) uint {
|
||||
}
|
||||
|
||||
// ToUint try to convert value to uint
|
||||
func ToUint(v any) (uint, error) {
|
||||
return mathutil.ToUint(v)
|
||||
}
|
||||
func ToUint(v any) (uint, error) { return mathutil.ToUint(v) }
|
||||
|
||||
// Uint64 convert value to uint64
|
||||
func Uint64(v any) uint64 {
|
||||
@@ -75,14 +65,10 @@ func Uint64(v any) uint64 {
|
||||
}
|
||||
|
||||
// ToUint64 try to convert value to uint64
|
||||
func ToUint64(v any) (uint64, error) {
|
||||
return mathutil.ToUint64(v)
|
||||
}
|
||||
func ToUint64(v any) (uint64, error) { return mathutil.ToUint64(v) }
|
||||
|
||||
// BoolString convert bool to string
|
||||
func BoolString(bl bool) string {
|
||||
return strconv.FormatBool(bl)
|
||||
}
|
||||
func BoolString(bl bool) string { return strconv.FormatBool(bl) }
|
||||
|
||||
// BaseTypeVal convert custom type or intX,uintX,floatX to generic base type.
|
||||
//
|
||||
@@ -136,7 +122,7 @@ func ConvOrDefault(val any, kind reflect.Kind, defVal any) any {
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// val, err := ToKind("123", reflect.Int) // 123
|
||||
// val, err := ToKind("123", reflect.Int) // 123
|
||||
func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newVal any, err error) {
|
||||
switch kind {
|
||||
case reflect.Int:
|
||||
|
||||
43
vendor/github.com/gookit/goutil/envutil/envutil.go
generated
vendored
43
vendor/github.com/gookit/goutil/envutil/envutil.go
generated
vendored
@@ -3,7 +3,9 @@ package envutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/internal/varexpr"
|
||||
)
|
||||
|
||||
@@ -42,36 +44,23 @@ func ParseValue(val string) string {
|
||||
}
|
||||
|
||||
// VarParse alias of the ParseValue
|
||||
func VarParse(val string) string {
|
||||
return varexpr.SafeParse(val)
|
||||
}
|
||||
func VarParse(val string) string { return varexpr.SafeParse(val) }
|
||||
|
||||
// ParseEnvValue alias of the ParseValue
|
||||
func ParseEnvValue(val string) string {
|
||||
return varexpr.SafeParse(val)
|
||||
func ParseEnvValue(val string) string { return varexpr.SafeParse(val) }
|
||||
|
||||
// SplitText2map parse ENV text to map. Can use to parse .env file contents.
|
||||
func SplitText2map(text string) map[string]string {
|
||||
envMp, _ := comfunc.ParseEnvLines(text, comfunc.ParseEnvLineOption{
|
||||
SkipOnErrorLine: true,
|
||||
})
|
||||
return envMp
|
||||
}
|
||||
|
||||
// SetEnvMap set multi ENV(string-map) to os
|
||||
func SetEnvMap(mp map[string]string) {
|
||||
for key, value := range mp {
|
||||
_ = os.Setenv(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// SetEnvs set multi k-v ENV pairs to os
|
||||
func SetEnvs(kvPairs ...string) {
|
||||
if len(kvPairs)%2 == 1 {
|
||||
panic("envutil.SetEnvs: odd argument count")
|
||||
}
|
||||
|
||||
for i := 0; i < len(kvPairs); i += 2 {
|
||||
_ = os.Setenv(kvPairs[i], kvPairs[i+1])
|
||||
}
|
||||
}
|
||||
|
||||
// UnsetEnvs from os
|
||||
func UnsetEnvs(keys ...string) {
|
||||
for _, key := range keys {
|
||||
_ = os.Unsetenv(key)
|
||||
// SplitLineToKv parse ENV line to k-v. eg: 'DEBUG=true' => ['DEBUG', 'true']
|
||||
func SplitLineToKv(line string) (string, string) {
|
||||
if line = strings.TrimSpace(line); line == "" {
|
||||
return "", ""
|
||||
}
|
||||
return comfunc.SplitLineToKv(line, "=")
|
||||
}
|
||||
|
||||
33
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
33
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
@@ -4,9 +4,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// Getenv get ENV value by key name, can with default value
|
||||
@@ -18,6 +18,14 @@ func Getenv(name string, def ...string) string {
|
||||
return val
|
||||
}
|
||||
|
||||
// MustGet get ENV value by key name, if not exists or empty, will panic
|
||||
func MustGet(name string) string {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
return val
|
||||
}
|
||||
panic("ENV key '" + name + "' not exists")
|
||||
}
|
||||
|
||||
// GetInt get int ENV value by key name, can with default value
|
||||
func GetInt(name string, def ...int) int {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
@@ -34,6 +42,20 @@ func GetBool(name string, def ...bool) bool {
|
||||
return basefn.FirstOr(def, false)
|
||||
}
|
||||
|
||||
// GetOne get one not empty ENV value by input names.
|
||||
func GetOne(names []string, defVal ...string) string {
|
||||
for _, name := range names {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMulti ENV values by input names.
|
||||
func GetMulti(names ...string) map[string]string {
|
||||
valMap := make(map[string]string, len(names))
|
||||
@@ -46,6 +68,15 @@ func GetMulti(names ...string) map[string]string {
|
||||
return valMap
|
||||
}
|
||||
|
||||
// OnExist check ENV value by key name, if exists call fn
|
||||
func OnExist(name string, fn func(val string)) bool {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
fn(val)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// EnvPaths get and split $PATH to []string
|
||||
func EnvPaths() []string {
|
||||
return filepath.SplitList(os.Getenv("PATH"))
|
||||
|
||||
29
vendor/github.com/gookit/goutil/envutil/info.go
generated
vendored
29
vendor/github.com/gookit/goutil/envutil/info.go
generated
vendored
@@ -36,33 +36,6 @@ func IsMSys() bool {
|
||||
return sysutil.IsMSys()
|
||||
}
|
||||
|
||||
var detectedWSL bool
|
||||
var detectedWSLContents string
|
||||
|
||||
// IsWSL system env
|
||||
// https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
|
||||
func IsWSL() 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
|
||||
f.Close()
|
||||
detectedWSLContents = string(b)
|
||||
}
|
||||
detectedWSL = true
|
||||
}
|
||||
return strings.Contains(detectedWSLContents, "Microsoft")
|
||||
}
|
||||
|
||||
// IsTerminal isatty check
|
||||
//
|
||||
@@ -114,7 +87,7 @@ var specialColorTerms = map[string]bool{
|
||||
//
|
||||
// Supported:
|
||||
//
|
||||
// linux, mac, or windows's ConEmu, Cmder, putty, git-bash.exe
|
||||
// linux, mac, or Windows's ConEmu, Cmder, putty, git-bash.exe
|
||||
//
|
||||
// Not support:
|
||||
//
|
||||
|
||||
52
vendor/github.com/gookit/goutil/envutil/set.go
generated
vendored
Normal file
52
vendor/github.com/gookit/goutil/envutil/set.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package envutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// SetEnvMap set multi ENV(string-map) to os
|
||||
func SetEnvMap(mp map[string]string) {
|
||||
for key, value := range mp {
|
||||
_ = os.Setenv(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// SetEnvs set multi k-v ENV pairs to os
|
||||
func SetEnvs(kvPairs ...string) {
|
||||
if len(kvPairs)%2 == 1 {
|
||||
panic("envutil.SetEnvs: odd argument count")
|
||||
}
|
||||
|
||||
for i := 0; i < len(kvPairs); i += 2 {
|
||||
_ = os.Setenv(kvPairs[i], kvPairs[i+1])
|
||||
}
|
||||
}
|
||||
|
||||
// UnsetEnvs from os
|
||||
func UnsetEnvs(keys ...string) {
|
||||
for _, key := range keys {
|
||||
_ = os.Unsetenv(key)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadText parse multiline text to ENV. Can use to load .env file contents.
|
||||
//
|
||||
// Usage:
|
||||
// envutil.LoadText(fsutil.ReadFile(".env"))
|
||||
func LoadText(text string) {
|
||||
envMp := SplitText2map(text)
|
||||
for key, value := range envMp {
|
||||
_ = os.Setenv(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadString set line to ENV. e.g.: KEY=VALUE
|
||||
func LoadString(line string) bool {
|
||||
k, v := comfunc.SplitLineToKv(line, "=")
|
||||
if len(k) > 0 {
|
||||
return os.Setenv(k, v) == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
35
vendor/github.com/gookit/goutil/errorx/util.go
generated
vendored
35
vendor/github.com/gookit/goutil/errorx/util.go
generated
vendored
@@ -6,34 +6,25 @@ import (
|
||||
)
|
||||
|
||||
// E new a raw go error. alias of errors.New()
|
||||
func E(msg string) error {
|
||||
return errors.New(msg)
|
||||
}
|
||||
func E(msg string) error { return errors.New(msg) }
|
||||
|
||||
// Err new a raw go error. alias of errors.New()
|
||||
func Err(msg string) error {
|
||||
return errors.New(msg)
|
||||
}
|
||||
func Err(msg string) error { return errors.New(msg) }
|
||||
|
||||
// Raw new a raw go error. alias of errors.New()
|
||||
func Raw(msg string) error {
|
||||
return errors.New(msg)
|
||||
}
|
||||
func Raw(msg string) error { return errors.New(msg) }
|
||||
|
||||
// Ef new a raw go error. alias of errors.New()
|
||||
func Ef(tpl string, vars ...any) error {
|
||||
return fmt.Errorf(tpl, vars...)
|
||||
}
|
||||
// Ef new a raw go error. alias of fmt.Errorf
|
||||
func Ef(tpl string, vars ...any) error { return fmt.Errorf(tpl, vars...) }
|
||||
|
||||
// Errf new a raw go error. alias of errors.New()
|
||||
func Errf(tpl string, vars ...any) error {
|
||||
return fmt.Errorf(tpl, vars...)
|
||||
}
|
||||
// Errf new a raw go error. alias of fmt.Errorf
|
||||
func Errf(tpl string, vars ...any) error { return fmt.Errorf(tpl, vars...) }
|
||||
|
||||
// Rawf new a raw go error. alias of errors.New()
|
||||
func Rawf(tpl string, vars ...any) error {
|
||||
return fmt.Errorf(tpl, vars...)
|
||||
}
|
||||
// Rf new a raw go error. alias of fmt.Errorf
|
||||
func Rf(tpl string, vs ...any) error { return fmt.Errorf(tpl, vs...) }
|
||||
|
||||
// Rawf new a raw go error. alias of fmt.Errorf
|
||||
func Rawf(tpl string, vs ...any) error { return fmt.Errorf(tpl, vs...) }
|
||||
|
||||
/*************************************************************
|
||||
* helper func for error
|
||||
@@ -74,7 +65,7 @@ func IsErrorX(err error) (ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// ToErrorX convert check
|
||||
// ToErrorX convert check. like errors.As()
|
||||
func ToErrorX(err error) (ex *ErrorX, ok bool) {
|
||||
ex, ok = err.(*ErrorX)
|
||||
return
|
||||
|
||||
2
vendor/github.com/gookit/goutil/fsutil/README.md
generated
vendored
2
vendor/github.com/gookit/goutil/fsutil/README.md
generated
vendored
@@ -14,6 +14,8 @@ go get github.com/gookit/goutil/fsutil
|
||||
|
||||
## Find files
|
||||
|
||||
More see [./finder](./finder)
|
||||
|
||||
```go
|
||||
// find all files in dir
|
||||
fsutil.FindInDir("./", func(filePath string, de fs.DirEntry) error {
|
||||
|
||||
14
vendor/github.com/gookit/goutil/fsutil/define.go
generated
vendored
14
vendor/github.com/gookit/goutil/fsutil/define.go
generated
vendored
@@ -12,16 +12,16 @@ const (
|
||||
MimeSniffLen = 512
|
||||
)
|
||||
|
||||
// NameMatchFunc name match func, alias of comdef.StringMatchFunc
|
||||
// NameMatchFunc name matches func, alias of comdef.StringMatchFunc
|
||||
type NameMatchFunc = comdef.StringMatchFunc
|
||||
|
||||
// PathMatchFunc path match func. alias of comdef.StringMatchFunc
|
||||
// PathMatchFunc path matches func. alias of comdef.StringMatchFunc
|
||||
type PathMatchFunc = comdef.StringMatchFunc
|
||||
|
||||
// Entry extends fs.DirEntry, add some useful methods
|
||||
type Entry interface {
|
||||
fs.DirEntry
|
||||
// Path get file/dir full path. eg: "/path/to/file.go"
|
||||
// Path gets file/dir full path. eg: "/path/to/file.go"
|
||||
Path() string
|
||||
// Info get file info. like fs.DirEntry.Info(), but will cache result.
|
||||
Info() (fs.FileInfo, error)
|
||||
@@ -42,12 +42,12 @@ func NewEntry(fPath string, ent fs.DirEntry) Entry {
|
||||
}
|
||||
}
|
||||
|
||||
// Path get full file/dir path. eg: "/path/to/file.go"
|
||||
// Path gets full file/dir path. eg: "/path/to/file.go"
|
||||
func (e *entry) Path() string {
|
||||
return e.path
|
||||
}
|
||||
|
||||
// Info get file info, will cache result
|
||||
// Info gets file info, will cache result
|
||||
func (e *entry) Info() (fs.FileInfo, error) {
|
||||
if e.stat == nil {
|
||||
e.stat, e.sErr = e.DirEntry.Info()
|
||||
@@ -63,7 +63,7 @@ func (e *entry) String() string {
|
||||
// FileInfo extends fs.FileInfo, add some useful methods
|
||||
type FileInfo interface {
|
||||
fs.FileInfo
|
||||
// Path get file full path. eg: "/path/to/file.go"
|
||||
// Path gets file full path. eg: "/path/to/file.go"
|
||||
Path() string
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func NewFileInfo(fPath string, info fs.FileInfo) FileInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Path get file full path. eg: "/path/to/file.go"
|
||||
// Path gets file full path. eg: "/path/to/file.go"
|
||||
func (fi *fileInfo) Path() string {
|
||||
return fi.fullPath
|
||||
}
|
||||
|
||||
37
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
37
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
@@ -11,19 +11,19 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// FilePathInDirs get full file path in dirs.
|
||||
// FilePathInDirs get full file path in dirs. return empty string if not found.
|
||||
//
|
||||
// Params:
|
||||
// - file: can be relative path, file name, full path.
|
||||
// - dirs: dir paths
|
||||
func FilePathInDirs(file string, dirs ...string) string {
|
||||
file = comfunc.ExpandHome(file)
|
||||
if FileExists(file) {
|
||||
return file
|
||||
func FilePathInDirs(fPath string, dirs ...string) string {
|
||||
fPath = comfunc.ExpandHome(fPath)
|
||||
if FileExists(fPath) {
|
||||
return fPath
|
||||
}
|
||||
|
||||
for _, dirPath := range dirs {
|
||||
fPath := JoinSubPaths(dirPath, file)
|
||||
fPath := JoinSubPaths(dirPath, fPath)
|
||||
if FileExists(fPath) {
|
||||
return fPath
|
||||
}
|
||||
@@ -102,12 +102,12 @@ func SearchNameUpx(dirPath, name string) (string, bool) {
|
||||
// WalkDir walks the file tree rooted at root, calling fn for each file or
|
||||
// directory in the tree, including root.
|
||||
//
|
||||
// TIP: will recursively find in sub dirs.
|
||||
// TIP: will recursively found in sub dirs.
|
||||
func WalkDir(dir string, fn fs.WalkDirFunc) error {
|
||||
return filepath.WalkDir(dir, fn)
|
||||
}
|
||||
|
||||
// Glob find files by glob path pattern. alias of filepath.Glob()
|
||||
// Glob finds files by glob path pattern. alias of filepath.Glob()
|
||||
// and support filter matched files by name.
|
||||
//
|
||||
// Usage:
|
||||
@@ -132,8 +132,6 @@ func Glob(pattern string, fls ...NameMatchFunc) []string {
|
||||
}
|
||||
|
||||
// GlobWithFunc find files by glob path pattern, then handle matched file
|
||||
//
|
||||
// - TIP: will be not find in subdir.
|
||||
func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) {
|
||||
files, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
@@ -207,7 +205,7 @@ func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool {
|
||||
|
||||
// FindInDir code refer the go pkg: path/filepath.glob()
|
||||
//
|
||||
// - TIP: will be not find in subdir.
|
||||
// - TIP: will be not found in sub-dir.
|
||||
//
|
||||
// filters: return false will skip the file.
|
||||
func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) {
|
||||
@@ -235,9 +233,22 @@ func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := handleFn(filePath, ent); err != nil {
|
||||
return err
|
||||
if err1 := handleFn(filePath, ent); err1 != nil {
|
||||
return err1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileInDirs returns the first file path in the given dirs.
|
||||
func FileInDirs(paths []string, names ...string) string {
|
||||
for _, pathDir := range paths {
|
||||
for _, name := range names {
|
||||
file := pathDir + "/" + name
|
||||
if IsFile(file) {
|
||||
return file
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
2
vendor/github.com/gookit/goutil/fsutil/fsutil.go
generated
vendored
2
vendor/github.com/gookit/goutil/fsutil/fsutil.go
generated
vendored
@@ -6,8 +6,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// PathSep alias of os.PathSeparator
|
||||
|
||||
59
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
59
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
@@ -3,39 +3,66 @@ package fsutil
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// DirPath get dir path from filepath, without last name.
|
||||
func DirPath(fpath string) string { return filepath.Dir(fpath) }
|
||||
// DirPath get dir path from filepath, without a last name.
|
||||
func DirPath(fPath string) string { return filepath.Dir(fPath) }
|
||||
|
||||
// Dir get dir path from filepath, without last name.
|
||||
func Dir(fpath string) string { return filepath.Dir(fpath) }
|
||||
// Dir get dir path from filepath, without a last name.
|
||||
func Dir(fPath string) string { return filepath.Dir(fPath) }
|
||||
|
||||
// PathName get file/dir name from full path
|
||||
func PathName(fpath string) string { return filepath.Base(fpath) }
|
||||
// PathName get file/dir name from a full path
|
||||
func PathName(fPath string) string { return filepath.Base(fPath) }
|
||||
|
||||
// PathNoExt get path from full path, without ext.
|
||||
//
|
||||
// eg: path/to/main.go => "path/to/main"
|
||||
func PathNoExt(fPath string) string {
|
||||
ext := filepath.Ext(fPath)
|
||||
if el := len(ext); el > 0 {
|
||||
return fPath[:len(fPath)-el]
|
||||
}
|
||||
return fPath
|
||||
}
|
||||
|
||||
// Name get file/dir name from full path.
|
||||
//
|
||||
// eg: path/to/main.go => main.go
|
||||
func Name(fpath string) string {
|
||||
if fpath == "" {
|
||||
// eg: path/to/main.go => "main.go"
|
||||
func Name(fPath string) string {
|
||||
if fPath == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Base(fpath)
|
||||
return filepath.Base(fPath)
|
||||
}
|
||||
|
||||
// NameNoExt get file name from a full path, without an ext.
|
||||
//
|
||||
// eg: path/to/main.go => "main"
|
||||
func NameNoExt(fPath string) string {
|
||||
if fPath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
fName := filepath.Base(fPath)
|
||||
if pos := strings.LastIndexByte(fName, '.'); pos > 0 {
|
||||
return fName[:pos]
|
||||
}
|
||||
return fName
|
||||
}
|
||||
|
||||
// FileExt get filename ext. alias of filepath.Ext()
|
||||
//
|
||||
// eg: path/to/main.go => ".go"
|
||||
func FileExt(fpath string) string { return filepath.Ext(fpath) }
|
||||
func FileExt(fPath string) string { return filepath.Ext(fPath) }
|
||||
|
||||
// Extname get filename ext. alias of filepath.Ext()
|
||||
//
|
||||
// eg: path/to/main.go => "go"
|
||||
func Extname(fpath string) string {
|
||||
if ext := filepath.Ext(fpath); len(ext) > 0 {
|
||||
func Extname(fPath string) string {
|
||||
if ext := filepath.Ext(fPath); len(ext) > 0 {
|
||||
return ext[1:]
|
||||
}
|
||||
return ""
|
||||
@@ -44,14 +71,14 @@ func Extname(fpath string) string {
|
||||
// Suffix get filename ext. alias of filepath.Ext()
|
||||
//
|
||||
// eg: path/to/main.go => ".go"
|
||||
func Suffix(fpath string) string { return filepath.Ext(fpath) }
|
||||
func Suffix(fPath string) string { return filepath.Ext(fPath) }
|
||||
|
||||
// Expand will parse first `~` as user home dir path.
|
||||
// Expand will parse first `~` to user home dir path.
|
||||
func Expand(pathStr string) string {
|
||||
return comfunc.ExpandHome(pathStr)
|
||||
}
|
||||
|
||||
// ExpandPath will parse `~` as user home dir path.
|
||||
// ExpandPath will parse `~` to user home dir path.
|
||||
func ExpandPath(pathStr string) string {
|
||||
return comfunc.ExpandHome(pathStr)
|
||||
}
|
||||
|
||||
2
vendor/github.com/gookit/goutil/fsutil/mime.go
generated
vendored
2
vendor/github.com/gookit/goutil/fsutil/mime.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// DetectMime detect file mime type. alias of MimeType()
|
||||
// DetectMime detect a file mime type. alias of MimeType()
|
||||
func DetectMime(path string) string {
|
||||
return MimeType(path)
|
||||
}
|
||||
|
||||
16
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
16
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// Mkdir alias of os.MkdirAll()
|
||||
@@ -17,7 +17,7 @@ func Mkdir(dirPath string, perm os.FileMode) error {
|
||||
return os.MkdirAll(dirPath, perm)
|
||||
}
|
||||
|
||||
// MkDirs batch make multi dirs at once
|
||||
// MkDirs batch makes multi dirs at once
|
||||
func MkDirs(perm os.FileMode, dirPaths ...string) error {
|
||||
for _, dirPath := range dirPaths {
|
||||
if err := os.MkdirAll(dirPath, perm); err != nil {
|
||||
@@ -27,7 +27,7 @@ func MkDirs(perm os.FileMode, dirPaths ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkSubDirs batch make multi sub-dirs at once
|
||||
// MkSubDirs batch makes multi sub-dirs at once
|
||||
func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error {
|
||||
for _, dirName := range subDirs {
|
||||
dirPath := parentDir + "/" + dirName
|
||||
@@ -38,7 +38,7 @@ func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkParentDir quick create parent dir for given path.
|
||||
// MkParentDir quickly create parent dir for a given path.
|
||||
func MkParentDir(fpath string) error {
|
||||
dirPath := filepath.Dir(fpath)
|
||||
if !IsDir(dirPath) {
|
||||
@@ -232,10 +232,10 @@ func SafeRemoveAll(path string) {
|
||||
_ = os.RemoveAll(path)
|
||||
}
|
||||
|
||||
// RmIfExist removes the named file or (empty) directory on exists.
|
||||
// RmIfExist removes the named file or (empty) directory on existing.
|
||||
func RmIfExist(fPath string) error { return DeleteIfExist(fPath) }
|
||||
|
||||
// DeleteIfExist removes the named file or (empty) directory on exists.
|
||||
// DeleteIfExist removes the named file or (empty) directory on existing.
|
||||
func DeleteIfExist(fPath string) error {
|
||||
if PathExists(fPath) {
|
||||
return os.Remove(fPath)
|
||||
@@ -243,10 +243,10 @@ func DeleteIfExist(fPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RmFileIfExist removes the named file on exists.
|
||||
// RmFileIfExist removes the named file on existing.
|
||||
func RmFileIfExist(fPath string) error { return DeleteIfFileExist(fPath) }
|
||||
|
||||
// DeleteIfFileExist removes the named file on exists.
|
||||
// DeleteIfFileExist removes the named file on existing.
|
||||
func DeleteIfFileExist(fPath string) error {
|
||||
if IsFile(fPath) {
|
||||
return os.Remove(fPath)
|
||||
|
||||
2
vendor/github.com/gookit/goutil/fsutil/opread.go
generated
vendored
2
vendor/github.com/gookit/goutil/fsutil/opread.go
generated
vendored
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"text/scanner"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// NewIOReader instance by input file path or io.Reader
|
||||
|
||||
17
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
17
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// ************************************************************
|
||||
@@ -74,9 +74,14 @@ func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error {
|
||||
return WriteFile(filePath, data, opt.Perm, opt.Flag)
|
||||
}
|
||||
|
||||
// PutContents create file and write contents to file at once.
|
||||
// WriteData Quick write any data to file, alias of PutContents
|
||||
func WriteData(filePath string, data any, fileFlag ...int) (int, error) {
|
||||
return PutContents(filePath, data, fileFlag...)
|
||||
}
|
||||
|
||||
// PutContents create file and write contents to file at once. Will auto create dir
|
||||
//
|
||||
// data type allow: string, []byte, io.Reader. will auto create dir.
|
||||
// data type allows: string, []byte, io.Reader
|
||||
//
|
||||
// Tip: file flag default is FsCWTFlags (override write)
|
||||
//
|
||||
@@ -92,9 +97,9 @@ func PutContents(filePath string, data any, fileFlag ...int) (int, error) {
|
||||
return WriteOSFile(f, data)
|
||||
}
|
||||
|
||||
// WriteFile create file and write contents to file, can set perm for file.
|
||||
// WriteFile create file and write contents to file, can set perm for a file.
|
||||
//
|
||||
// data type allow: string, []byte, io.Reader
|
||||
// data type allows: string, []byte, io.Reader
|
||||
//
|
||||
// Tip: file flag default is FsCWTFlags (override write)
|
||||
//
|
||||
@@ -114,7 +119,7 @@ func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) err
|
||||
|
||||
// WriteOSFile write data to give os.File, then close file.
|
||||
//
|
||||
// data type allow: string, []byte, io.Reader
|
||||
// data type allows: string, []byte, io.Reader
|
||||
func WriteOSFile(f *os.File, data any) (n int, err error) {
|
||||
switch typData := data.(type) {
|
||||
case []byte:
|
||||
|
||||
10
vendor/github.com/gookit/goutil/func.go
generated
vendored
10
vendor/github.com/gookit/goutil/func.go
generated
vendored
@@ -23,6 +23,14 @@ func CallOn(cond bool, fn ErrFunc) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IfElseFn call okFunc() on condition is true, else call elseFn()
|
||||
func IfElseFn(cond bool, okFn, elseFn ErrFunc) error {
|
||||
if cond {
|
||||
return okFn()
|
||||
}
|
||||
return elseFn()
|
||||
}
|
||||
|
||||
// CallOrElse call okFunc() on condition is true, else call elseFn()
|
||||
func CallOrElse(cond bool, okFn, elseFn ErrFunc) error {
|
||||
if cond {
|
||||
@@ -43,7 +51,7 @@ func SafeRun(fn func()) (err error) {
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// SafeRunWithError sync run a func with error.
|
||||
|
||||
130
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
130
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
@@ -1,13 +1,16 @@
|
||||
// Package goutil 💪 Useful utils for Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem,
|
||||
// Package goutil 💪 Useful utils for Go: byte, int, string, array/slice, map, struct, reflect, error, time, format, CLI, ENV, filesystem,
|
||||
// system, testing, debug and more.
|
||||
package goutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/goinfo"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
"github.com/gookit/goutil/structs"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
"github.com/gookit/goutil/x/goinfo"
|
||||
)
|
||||
|
||||
// Value alias of structs.Value
|
||||
@@ -18,7 +21,7 @@ func Panicf(format string, v ...any) {
|
||||
panic(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// PanicIf if cond = true, panics with error message
|
||||
// PanicIf if cond = true, panics with an error message
|
||||
func PanicIf(cond bool, fmtAndArgs ...any) {
|
||||
basefn.PanicIf(cond, fmtAndArgs...)
|
||||
}
|
||||
@@ -74,21 +77,6 @@ func Must[T any](v T, err error) T {
|
||||
return v
|
||||
}
|
||||
|
||||
// FuncName get func name
|
||||
func FuncName(f any) string {
|
||||
return goinfo.FuncName(f)
|
||||
}
|
||||
|
||||
// PkgName get current package name. alias of goinfo.PkgName()
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// funcName := goutil.FuncName(fn)
|
||||
// pgkName := goutil.PkgName(funcName)
|
||||
func PkgName(funcName string) string {
|
||||
return goinfo.PkgName(funcName)
|
||||
}
|
||||
|
||||
// ErrOnFail return input error on cond is false, otherwise return nil
|
||||
func ErrOnFail(cond bool, err error) error {
|
||||
return OrError(cond, err)
|
||||
@@ -102,7 +90,7 @@ func OrError(cond bool, err error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OrValue get
|
||||
// OrValue get. like: if cond { okVal } else { elVal }
|
||||
func OrValue[T any](cond bool, okVal, elVal T) T {
|
||||
if cond {
|
||||
return okVal
|
||||
@@ -117,3 +105,105 @@ func OrReturn[T any](cond bool, okFn, elseFn func() T) T {
|
||||
}
|
||||
return elseFn()
|
||||
}
|
||||
|
||||
//
|
||||
// ------------------------- check functions -------------------------
|
||||
//
|
||||
|
||||
// IsNil value check
|
||||
func IsNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsNil(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsZero value check, alias of the IsEmpty()
|
||||
var IsZero = IsEmpty
|
||||
|
||||
// IsEmpty value check
|
||||
func IsEmpty(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsEmpty(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsZeroReal Alias of the IsEmptyReal()
|
||||
var IsZeroReal = IsEmptyReal
|
||||
|
||||
// IsEmptyReal checks for empty given value and also real empty value if the passed value is a pointer
|
||||
func IsEmptyReal(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsEmptyReal(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsFunc value
|
||||
func IsFunc(val any) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
return reflect.TypeOf(val).Kind() == reflect.Func
|
||||
}
|
||||
|
||||
// IsEqual determines if two objects are considered equal.
|
||||
//
|
||||
// TIP: cannot compare a function type
|
||||
func IsEqual(src, dst any) bool {
|
||||
if src == nil || dst == nil {
|
||||
return src == dst
|
||||
}
|
||||
|
||||
// cannot compare a function type
|
||||
if IsFunc(src) || IsFunc(dst) {
|
||||
return false
|
||||
}
|
||||
return reflects.IsEqual(src, dst)
|
||||
}
|
||||
|
||||
// Contains try loop over the data check if the data includes the element.
|
||||
// alias of the IsContains
|
||||
//
|
||||
// TIP: only support types: string, map, array, slice
|
||||
//
|
||||
// map - check key exists
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func Contains(data, elem any) bool {
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
|
||||
// IsContains try loop over the data check if the data includes the element.
|
||||
//
|
||||
// TIP: only support types: string, map, array, slice
|
||||
//
|
||||
// map - check key exists
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func IsContains(data, elem any) bool {
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
|
||||
//
|
||||
// ------------------------- goinfo functions -------------------------
|
||||
//
|
||||
|
||||
// FuncName get func name
|
||||
func FuncName(f any) string {
|
||||
return goinfo.FuncName(f)
|
||||
}
|
||||
|
||||
// PkgName get the current package name. alias of goinfo.PkgName()
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// funcName := goutil.FuncName(fn)
|
||||
// pgkName := goutil.PkgName(funcName)
|
||||
func PkgName(funcName string) string {
|
||||
return goinfo.PkgName(funcName)
|
||||
}
|
||||
|
||||
|
||||
5
vendor/github.com/gookit/goutil/group.go
generated
vendored
5
vendor/github.com/gookit/goutil/group.go
generated
vendored
@@ -11,12 +11,12 @@ import (
|
||||
// are part of the same overall task.
|
||||
type ErrGroup = syncs.ErrGroup
|
||||
|
||||
// NewCtxErrGroup instance
|
||||
// NewCtxErrGroup instance. use for batch run tasks, can with context.
|
||||
func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) {
|
||||
return syncs.NewCtxErrGroup(ctx, limit...)
|
||||
}
|
||||
|
||||
// NewErrGroup instance
|
||||
// NewErrGroup instance. use for batch run tasks
|
||||
func NewErrGroup(limit ...int) *ErrGroup {
|
||||
return syncs.NewErrGroup(limit...)
|
||||
}
|
||||
@@ -48,7 +48,6 @@ func (p *QuickRun) Add(fns ...RunFn) *QuickRun {
|
||||
func (p *QuickRun) Run() error {
|
||||
for i, fn := range p.fns {
|
||||
p.ctx.Set("index", i)
|
||||
|
||||
if err := fn(p.ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
5
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
5
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
@@ -123,3 +123,8 @@ var numReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
|
||||
|
||||
// IsNumeric returns true if the given string is a numeric, otherwise false.
|
||||
func IsNumeric(s string) bool { return numReg.MatchString(s) }
|
||||
|
||||
// IsHttpURL check input is http/https url
|
||||
func IsHttpURL(s string) bool {
|
||||
return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
|
||||
}
|
||||
|
||||
40
vendor/github.com/gookit/goutil/internal/checkfn/sysenv.go
generated
vendored
Normal file
40
vendor/github.com/gookit/goutil/internal/checkfn/sysenv.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package checkfn
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var detectedWSL bool
|
||||
var detectedWSLContents string
|
||||
|
||||
// IsWSL system env
|
||||
// https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
|
||||
func IsWSL() bool {
|
||||
// ENV:
|
||||
// WSL_DISTRO_NAME=Debian
|
||||
if len(os.Getenv("WSL_DISTRO_NAME")) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
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
|
||||
f.Close()
|
||||
detectedWSLContents = string(b)
|
||||
}
|
||||
detectedWSL = true
|
||||
}
|
||||
return strings.Contains(detectedWSLContents, "Microsoft")
|
||||
}
|
||||
2
vendor/github.com/gookit/goutil/internal/comfunc/README.md
generated
vendored
2
vendor/github.com/gookit/goutil/internal/comfunc/README.md
generated
vendored
@@ -1,3 +1,3 @@
|
||||
# common func for internal use
|
||||
# Common func for internal use
|
||||
|
||||
- don't depend on other external packages
|
||||
93
vendor/github.com/gookit/goutil/internal/comfunc/cli_func.go
generated
vendored
Normal file
93
vendor/github.com/gookit/goutil/internal/comfunc/cli_func.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cmdline build
|
||||
func Cmdline(args []string, binName ...string) string {
|
||||
b := new(strings.Builder)
|
||||
|
||||
if len(binName) > 0 {
|
||||
b.WriteString(binName[0])
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
for i, a := range args {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
if strings.ContainsRune(a, '"') {
|
||||
b.WriteString(fmt.Sprintf(`'%s'`, a))
|
||||
} else if a == "" || strings.ContainsRune(a, '\'') || strings.ContainsRune(a, ' ') {
|
||||
b.WriteString(fmt.Sprintf(`"%s"`, a))
|
||||
} else {
|
||||
b.WriteString(a)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// ShellQuote quote a string on contains ', ", SPACE. refer strconv.Quote()
|
||||
func ShellQuote(a string) string {
|
||||
if a == "" {
|
||||
return `""`
|
||||
}
|
||||
|
||||
// use quote char
|
||||
var quote byte
|
||||
|
||||
// has double quote
|
||||
if pos := strings.IndexByte(a, '"'); pos > -1 {
|
||||
if !checkNeedQuote(a, pos, '"') {
|
||||
return a
|
||||
}
|
||||
|
||||
quote = '\''
|
||||
} else if pos := strings.IndexByte(a, '\''); pos > -1 {
|
||||
// single quote
|
||||
if !checkNeedQuote(a, pos, '\'') {
|
||||
return a
|
||||
}
|
||||
quote = '"'
|
||||
} else if strings.IndexByte(a, ' ') > -1 {
|
||||
quote = '"'
|
||||
}
|
||||
|
||||
// no quote char OR not need quote
|
||||
if quote == 0 {
|
||||
return a
|
||||
}
|
||||
return fmt.Sprintf("%c%s%c", quote, a, quote)
|
||||
}
|
||||
|
||||
func checkNeedQuote(a string, pos int, char byte) bool {
|
||||
// end with char. eg: "
|
||||
lastIsQ := a[len(a)-1] == char
|
||||
|
||||
// start with char. eg: "
|
||||
if pos == 0 {
|
||||
if lastIsQ {
|
||||
return false
|
||||
}
|
||||
|
||||
if pos1 := strings.IndexByte(a[pos+1:], char); pos1 > -1 {
|
||||
// eg: `"one two" three four`
|
||||
lastS := a[pos1+pos+1:]
|
||||
if !strings.ContainsRune(lastS, ' ') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startS := a[:pos]
|
||||
|
||||
// eg: `--one="two three"`
|
||||
if lastIsQ && strings.IndexByte(startS, ' ') == -1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
31
vendor/github.com/gookit/goutil/internal/comfunc/cmdline.go
generated
vendored
31
vendor/github.com/gookit/goutil/internal/comfunc/cmdline.go
generated
vendored
@@ -1,31 +0,0 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cmdline build
|
||||
func Cmdline(args []string, binName ...string) string {
|
||||
b := new(strings.Builder)
|
||||
|
||||
if len(binName) > 0 {
|
||||
b.WriteString(binName[0])
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
for i, a := range args {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
if strings.ContainsRune(a, '"') {
|
||||
b.WriteString(fmt.Sprintf(`'%s'`, a))
|
||||
} else if a == "" || strings.ContainsRune(a, '\'') || strings.ContainsRune(a, ' ') {
|
||||
b.WriteString(fmt.Sprintf(`"%s"`, a))
|
||||
} else {
|
||||
b.WriteString(a)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
79
vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go
generated
vendored
79
vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go
generated
vendored
@@ -1,12 +1,8 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Environ like os.Environ, but will returns key-value map[string]string data.
|
||||
@@ -24,78 +20,3 @@ func Environ() map[string]string {
|
||||
}
|
||||
return envMap
|
||||
}
|
||||
|
||||
var (
|
||||
// TIP: extend unit d,w. eg: "1d", "2w"
|
||||
// time.ParseDuration() is max support hour "h".
|
||||
durStrReg = regexp.MustCompile(`^(-?\d+)(ns|us|µs|ms|s|m|h|d|w)$`)
|
||||
|
||||
// match long duration string. eg: "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks", "1month"
|
||||
// time.ParseDuration() is not supported.
|
||||
durStrRegL = regexp.MustCompile(`^(-?\d+)([hdmsw][a-zA-Z]{2,8})$`)
|
||||
)
|
||||
|
||||
// IsDuration check the string is a duration string.
|
||||
func IsDuration(s string) bool {
|
||||
if s == "0" || durStrReg.MatchString(s) {
|
||||
return true
|
||||
}
|
||||
return durStrRegL.MatchString(s)
|
||||
}
|
||||
|
||||
// ToDuration parses a duration string. such as "300ms", "-1.5h" or "2h45m".
|
||||
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||
//
|
||||
// Diff of time.ParseDuration:
|
||||
// - support extend unit d, w at the end of string. such as "1d", "2w".
|
||||
// - support long string unit at end. such as "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks".
|
||||
//
|
||||
// If the string is not a valid duration string, it will return an error.
|
||||
func ToDuration(s string) (time.Duration, error) {
|
||||
ln := len(s)
|
||||
if ln == 0 {
|
||||
return 0, fmt.Errorf("empty duration string")
|
||||
}
|
||||
|
||||
s = strings.ToLower(s)
|
||||
if s == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// extend unit d,w, time.ParseDuration() is not supported. eg: "1d", "2w"
|
||||
if lastUnit := s[ln-1]; lastUnit == 'd' {
|
||||
s = s + "ay"
|
||||
} else if lastUnit == 'w' {
|
||||
s = s + "eek"
|
||||
}
|
||||
|
||||
// long unit, time.ParseDuration() is not supported. eg: "-3sec" => [3sec -3 sec]
|
||||
ss := durStrRegL.FindStringSubmatch(s)
|
||||
if len(ss) == 3 {
|
||||
num, unit := ss[1], ss[2]
|
||||
|
||||
// convert to short unit
|
||||
switch unit {
|
||||
case "month", "months":
|
||||
// max unit is hour, so need convert by 24 * 30 * n
|
||||
n, _ := strconv.Atoi(num)
|
||||
s = strconv.Itoa(n*24*30) + "h"
|
||||
case "week", "weeks":
|
||||
// max unit is hour, so need convert by 24 * 7 * n
|
||||
n, _ := strconv.Atoi(num)
|
||||
s = strconv.Itoa(n*24*7) + "h"
|
||||
case "day", "days":
|
||||
// max unit is hour, so need convert by 24 * n
|
||||
n, _ := strconv.Atoi(num)
|
||||
s = strconv.Itoa(n*24) + "h"
|
||||
case "hour", "hours":
|
||||
s = num + "h"
|
||||
case "min", "mins", "minute", "minutes":
|
||||
s = num + "m"
|
||||
case "sec", "secs", "second", "seconds":
|
||||
s = num + "s"
|
||||
}
|
||||
}
|
||||
|
||||
return time.ParseDuration(s)
|
||||
}
|
||||
|
||||
95
vendor/github.com/gookit/goutil/internal/comfunc/str_func.go
generated
vendored
Normal file
95
vendor/github.com/gookit/goutil/internal/comfunc/str_func.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var commentsPrefixes = []string{"#", ";", "//"}
|
||||
|
||||
// ParseEnvLineOption parse env line options
|
||||
type ParseEnvLineOption struct {
|
||||
// NotInlineComments dont parse inline comments.
|
||||
// - default: false. will parse inline comments
|
||||
NotInlineComments bool
|
||||
// SkipOnErrorLine skip error line, continue parse next line
|
||||
// - False: return error, clear parsed map
|
||||
SkipOnErrorLine bool
|
||||
}
|
||||
|
||||
// ParseEnvLines parse simple multiline k-v string to a string-map.
|
||||
// Can use to parse simple INI or DOTENV file contents.
|
||||
//
|
||||
// NOTE:
|
||||
//
|
||||
// - It's like INI/ENV format contents.
|
||||
// - Support comments line starts with: "#", ";", "//"
|
||||
// - Support inline comments split with: " #" eg: name=tom # a comments
|
||||
// - DON'T support submap parse.
|
||||
func ParseEnvLines(text string, opt ParseEnvLineOption) (mp map[string]string, err error) {
|
||||
lines := strings.Split(text, "\n")
|
||||
ln := len(lines)
|
||||
if ln == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
strMap := make(map[string]string, ln)
|
||||
|
||||
for _, line := range lines {
|
||||
if line = strings.TrimSpace(line); line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// skip comments line
|
||||
if line[0] == '#' || line[0] == ';' || strings.HasPrefix(line, "//") {
|
||||
continue
|
||||
}
|
||||
|
||||
// invalid line
|
||||
if strings.IndexByte(line, '=') < 1 {
|
||||
if opt.SkipOnErrorLine {
|
||||
continue
|
||||
}
|
||||
|
||||
strMap = nil
|
||||
err = fmt.Errorf("invalid line contents: must match `KEY=VAL`(line: %s)", line)
|
||||
return
|
||||
}
|
||||
|
||||
key, value := SplitLineToKv(line, "=")
|
||||
|
||||
// check and remove inline comments
|
||||
if !opt.NotInlineComments {
|
||||
if pos := strings.Index(value, " #"); pos > 0 {
|
||||
value = strings.TrimRight(value[0:pos], " \t")
|
||||
}
|
||||
}
|
||||
|
||||
strMap[key] = value
|
||||
}
|
||||
|
||||
return strMap, nil
|
||||
}
|
||||
|
||||
// SplitLineToKv parse string line to k-v. eg:
|
||||
//
|
||||
// 'DEBUG=true' => ['DEBUG', 'true']
|
||||
//
|
||||
// NOTE: line must contain '=', allow: 'ENV_KEY='
|
||||
func SplitLineToKv(line, sep string) (string, string) {
|
||||
nodes := strings.SplitN(line, sep, 2)
|
||||
envKey := strings.TrimSpace(nodes[0])
|
||||
|
||||
// key cannot be empty
|
||||
if envKey == "" {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
if len(nodes) < 2 {
|
||||
if strings.Contains(line, sep) {
|
||||
return envKey, ""
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
return envKey, strings.TrimSpace(nodes[1])
|
||||
}
|
||||
57
vendor/github.com/gookit/goutil/internal/comfunc/sysfunc.go
generated
vendored
57
vendor/github.com/gookit/goutil/internal/comfunc/sysfunc.go
generated
vendored
@@ -1,7 +1,6 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -51,6 +50,11 @@ func ExecCmd(binName string, args []string, workDir ...string) (string, error) {
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
var (
|
||||
cmdList = []string{"cmd", "cmd.exe"}
|
||||
pwshList = []string{"powershell", "powershell.exe", "pwsh", "pwsh.exe"}
|
||||
)
|
||||
|
||||
// ShellExec exec command by shell
|
||||
// cmdLine e.g. "ls -al"
|
||||
func ShellExec(cmdLine string, shells ...string) (string, error) {
|
||||
@@ -60,48 +64,63 @@ func ShellExec(cmdLine string, shells ...string) (string, error) {
|
||||
shell = shells[0]
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
cmd := exec.Command(shell, "-c", cmdLine)
|
||||
cmd.Stdout = &out
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return out.String(), nil
|
||||
bs, err := cmd.Output()
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// curShell cache
|
||||
var curShell string
|
||||
// curShellCache value
|
||||
var curShellCache string
|
||||
|
||||
// CurrentShell get current used shell env file.
|
||||
//
|
||||
// eg "/bin/zsh" "/bin/bash".
|
||||
// if onlyName=true, will return "zsh", "bash"
|
||||
func CurrentShell(onlyName bool) (binPath string) {
|
||||
// return like: "/bin/zsh" "/bin/bash". if onlyName=true, will return "zsh", "bash"
|
||||
func CurrentShell(onlyName bool, fallbackShell ...string) (binPath string) {
|
||||
var err error
|
||||
if curShell == "" {
|
||||
binPath = os.Getenv("SHELL")
|
||||
|
||||
fbShell := ""
|
||||
if len(fallbackShell) > 0 {
|
||||
fbShell = fallbackShell[0]
|
||||
}
|
||||
|
||||
if curShellCache == "" {
|
||||
// 检查父进程名称
|
||||
parentProcess := os.Getenv("GOPROCESS")
|
||||
if parentProcess != "" {
|
||||
return parentProcess
|
||||
}
|
||||
|
||||
binPath = os.Getenv("SHELL") // 适用于 Unix-like 系统
|
||||
if len(binPath) == 0 {
|
||||
// TODO check on Windows
|
||||
binPath, err = ShellExec("echo $SHELL")
|
||||
if err != nil {
|
||||
return ""
|
||||
return fbShell
|
||||
}
|
||||
}
|
||||
|
||||
binPath = strings.TrimSpace(binPath)
|
||||
// cache result
|
||||
curShell = binPath
|
||||
curShellCache = binPath
|
||||
} else {
|
||||
binPath = curShell
|
||||
binPath = curShellCache
|
||||
}
|
||||
|
||||
if onlyName && len(binPath) > 0 {
|
||||
binPath = filepath.Base(binPath)
|
||||
} else if len(binPath) == 0 {
|
||||
binPath = fbShell
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkWinCurrentShell() string {
|
||||
// 在 Windows 上,可以检查 COMSPEC 环境变量
|
||||
comSpec := os.Getenv("COMSPEC")
|
||||
// 没法检查 pwsh, 返回的还是 cmd
|
||||
return comSpec
|
||||
}
|
||||
|
||||
// HasShellEnv has shell env check.
|
||||
//
|
||||
// Usage:
|
||||
|
||||
149
vendor/github.com/gookit/goutil/internal/comfunc/time_func.go
generated
vendored
Normal file
149
vendor/github.com/gookit/goutil/internal/comfunc/time_func.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
package comfunc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// check is duration string. TIP: extend unit d,w. eg: "1d", "2w"
|
||||
//
|
||||
// time.ParseDuration() is max support hour "h".
|
||||
durStrReg = regexp.MustCompile(`^-?([0-9]+(?:\.[0-9]*)?(ns|us|µs|ms|s|m|h|d|w))+$`)
|
||||
|
||||
// check long duration string. 验证整体格式是否符合
|
||||
//
|
||||
// eg: "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks", "1month"
|
||||
//
|
||||
// time.ParseDuration() is not support long unit.
|
||||
durStrRegL = regexp.MustCompile(`^-?([0-9]+(?:\.[0-9]*)?[nuµsmhdw][a-zA-Z]{0,8})+$`)
|
||||
// use for parse duration string. see ToDuration()
|
||||
//
|
||||
// NOTE: 解析时,不能加最后的 `+` 会导致只匹配了最后一组 时间单位
|
||||
durStrRegL2 = regexp.MustCompile(`-?([0-9]+(?:\.[0-9]*)?)([nuµsmhdw][a-z]{0,8})`)
|
||||
)
|
||||
|
||||
// IsDuration check the string is a duration string.
|
||||
func IsDuration(s string) bool {
|
||||
if s == "0" || durStrReg.MatchString(s) {
|
||||
return true
|
||||
}
|
||||
return durStrRegL.MatchString(s)
|
||||
}
|
||||
|
||||
// ToDuration parses a duration string. such as "300ms", "-1.5h" or "2h45m".
|
||||
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||
//
|
||||
// Diff of time.ParseDuration:
|
||||
// - support extends unit d, w at the end of string. such as "1d", "2w".
|
||||
// - support extends unit: month, week, day
|
||||
// - support long string unit at the end. such as "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks".
|
||||
//
|
||||
// If the string is not a valid duration string, it will return an error.
|
||||
func ToDuration(s string) (time.Duration, error) {
|
||||
ln := len(s)
|
||||
if ln == 0 {
|
||||
return 0, fmt.Errorf("empty duration string")
|
||||
}
|
||||
|
||||
s = strings.ToLower(s)
|
||||
if s == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// check duration string is valid
|
||||
if !durStrRegL.MatchString(s) {
|
||||
return 0, fmt.Errorf("invalid duration string: %s", s)
|
||||
}
|
||||
|
||||
// if ln < 4 AND end != d|w, directly call time.ParseDuration()
|
||||
if ln < 4 && s[ln-1] != 'd' && s[ln-1] != 'w' {
|
||||
return time.ParseDuration(s)
|
||||
}
|
||||
|
||||
// time.ParseDuration() is not support long unit.
|
||||
ssList := durStrRegL2.FindAllStringSubmatch(s, -1)
|
||||
// fmt.Println(ssList)
|
||||
bts := make([]byte, 0, ln)
|
||||
if s[0] == '-' {
|
||||
bts = append(bts, '-')
|
||||
}
|
||||
|
||||
// only one element. eg: "1day"
|
||||
if len(ssList) == 1 {
|
||||
bts = parseLongUnit(ssList[0], bts)
|
||||
} else {
|
||||
// more than one element. eg: "1day2hour3min"
|
||||
for _, ss := range ssList {
|
||||
if len(ss) == 3 {
|
||||
bts = parseLongUnit(ss, bts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return time.ParseDuration(string(bts))
|
||||
}
|
||||
|
||||
// convert to short unit
|
||||
func parseLongUnit(ss []string, bts []byte) []byte {
|
||||
// eg: "3sec" -> ss=[3sec, -3, sec]
|
||||
num, unit := ss[1], ss[2]
|
||||
switch unit {
|
||||
case "month", "months":
|
||||
// time lib max unit is hour, so need convert by 24 * 30*n
|
||||
bts = appendNumToBytes(bts, num, 24*30)
|
||||
bts = append(bts, 'h')
|
||||
case "w", "week", "weeks":
|
||||
// time lib max unit is hour, so need convert by 24 * 7*n
|
||||
bts = appendNumToBytes(bts, num, 24*7)
|
||||
bts = append(bts, 'h')
|
||||
case "d", "day", "days":
|
||||
// time lib max unit is hour, so need convert by 24*n
|
||||
bts = appendNumToBytes(bts, num, 24)
|
||||
bts = append(bts, 'h')
|
||||
case "hour", "hours":
|
||||
bts = append(bts, num...)
|
||||
bts = append(bts, 'h')
|
||||
case "min", "mins", "minute", "minutes":
|
||||
bts = append(bts, num...)
|
||||
bts = append(bts, 'm')
|
||||
case "sec", "secs", "second", "seconds":
|
||||
bts = append(bts, num...)
|
||||
bts = append(bts, 's')
|
||||
default:
|
||||
first := ss[0]
|
||||
|
||||
// '-' has been added on ToDuration()
|
||||
if first[0] == '-' {
|
||||
bts = append(bts, first[1:]...)
|
||||
} else {
|
||||
bts = append(bts, first...)
|
||||
}
|
||||
}
|
||||
|
||||
return bts
|
||||
}
|
||||
|
||||
func appendNumToBytes(bts []byte, num string, multiple int) []byte {
|
||||
if strings.ContainsRune(num, '.') {
|
||||
f, _ := strconv.ParseFloat(num, 64) // is float number
|
||||
val := f * float64(multiple)
|
||||
|
||||
// 使用 Float 保留两位小数 -> 会始终有两位小数,即使是N.00
|
||||
// bts = strconv.AppendFloat(bts, val, 'f', 2, 64)
|
||||
|
||||
// 四舍五入到两位小数
|
||||
rounded := math.Round(val*100) / 100
|
||||
// 使用 AppendFloat 自动去除末尾的 .0 或 .00
|
||||
bts = strconv.AppendFloat(bts, rounded, 'f', -1, 64)
|
||||
} else {
|
||||
n, _ := strconv.Atoi(num)
|
||||
bts = strconv.AppendInt(bts, int64(n*multiple), 10)
|
||||
}
|
||||
|
||||
return bts
|
||||
}
|
||||
5
vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go
generated
vendored
5
vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go
generated
vendored
@@ -62,11 +62,15 @@ var std = New()
|
||||
// ${var_name} Only var name
|
||||
// ${var_name | default} With default value
|
||||
// ${var_name | ?error} With error on value is empty.
|
||||
//
|
||||
// see Parser.Parse
|
||||
func Parse(val string) (string, error) {
|
||||
return std.Parse(val)
|
||||
}
|
||||
|
||||
// SafeParse parse ENV var value from input string, support default value.
|
||||
//
|
||||
// see Parser.Parse
|
||||
func SafeParse(val string) string {
|
||||
s, _ := std.Parse(val)
|
||||
return s
|
||||
@@ -100,6 +104,7 @@ func New(optFns ...ParseOptFn) *Parser {
|
||||
// ${var_name} Only var name
|
||||
// ${var_name | default} With default value
|
||||
// ${var_name | ?error} With error on value is empty.
|
||||
// ${VAR_NAME1}/path/${VAR_NAME2} Allow multi var name.
|
||||
func (p *Parser) Parse(val string) (newVal string, err error) {
|
||||
if p.Regexp == nil {
|
||||
p.useDefaultRegex()
|
||||
|
||||
11
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
11
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// MustString encode data to json string, will panic on error
|
||||
@@ -62,3 +63,13 @@ func DecodeString(str string, ptr any) error {
|
||||
func DecodeReader(r io.Reader, ptr any) error {
|
||||
return json.NewDecoder(r).Decode(ptr)
|
||||
}
|
||||
|
||||
// DecodeFile decode JSON from file, bind data to ptr.
|
||||
func DecodeFile(file string, ptr any) error {
|
||||
bs, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return json.Unmarshal(bs, ptr)
|
||||
}
|
||||
113
vendor/github.com/gookit/goutil/maputil/convert.go
generated
vendored
113
vendor/github.com/gookit/goutil/maputil/convert.go
generated
vendored
@@ -11,8 +11,20 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// alias functions
|
||||
var (
|
||||
// ToStrMap convert map[string]any to map[string]string
|
||||
ToStrMap = ToStringMap
|
||||
// ToL2StrMap convert map[string]any to map[string]map[string]string
|
||||
ToL2StrMap = ToL2StringMap
|
||||
)
|
||||
|
||||
// KeyToLower convert keys to lower case.
|
||||
func KeyToLower(src map[string]string) map[string]string {
|
||||
if len(src) == 0 {
|
||||
return src
|
||||
}
|
||||
|
||||
newMp := make(map[string]string, len(src))
|
||||
for k, v := range src {
|
||||
k = strings.ToLower(k)
|
||||
@@ -21,7 +33,22 @@ func KeyToLower(src map[string]string) map[string]string {
|
||||
return newMp
|
||||
}
|
||||
|
||||
// ToStringMap convert map[string]any to map[string]string
|
||||
// AnyToStrMap try convert any(map[string]any, map[string]string) to map[string]string
|
||||
func AnyToStrMap(src any) map[string]string {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if m, ok := src.(map[string]string); ok {
|
||||
return m
|
||||
}
|
||||
if m, ok := src.(map[string]any); ok {
|
||||
return ToStringMap(m)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStringMap simple convert map[string]any to map[string]string
|
||||
func ToStringMap(src map[string]any) map[string]string {
|
||||
strMp := make(map[string]string, len(src))
|
||||
for k, v := range src {
|
||||
@@ -30,7 +57,25 @@ func ToStringMap(src map[string]any) map[string]string {
|
||||
return strMp
|
||||
}
|
||||
|
||||
// CombineToSMap combine two string-slice to SMap(map[string]string)
|
||||
// ToL2StringMap convert map[string]any to map[string]map[string]string
|
||||
func ToL2StringMap(groupsMap map[string]any) map[string]map[string]string {
|
||||
if len(groupsMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
l2sMap := make(map[string]map[string]string, len(groupsMap))
|
||||
|
||||
for k, v := range groupsMap {
|
||||
if mp, ok := v.(map[string]any); ok {
|
||||
l2sMap[k] = ToStringMap(mp)
|
||||
} else if smp, ok := v.(map[string]string); ok {
|
||||
l2sMap[k] = smp
|
||||
}
|
||||
}
|
||||
return l2sMap
|
||||
}
|
||||
|
||||
// CombineToSMap combine two string-slices to SMap(map[string]string)
|
||||
func CombineToSMap(keys, values []string) SMap {
|
||||
return arrutil.CombineToSMap(keys, values)
|
||||
}
|
||||
@@ -40,6 +85,54 @@ func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V {
|
||||
return arrutil.CombineToMap(keys, values)
|
||||
}
|
||||
|
||||
// SliceToSMap convert string k-v pairs slice to map[string]string
|
||||
// - eg: []string{k1,v1,k2,v2} -> map[string]string{k1:v1, k2:v2}
|
||||
func SliceToSMap(kvPairs ...string) map[string]string {
|
||||
ln := len(kvPairs)
|
||||
// check kvPairs length must be even
|
||||
if ln == 0 || ln%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sMap := make(map[string]string, ln/2)
|
||||
for i := 0; i < ln; i += 2 {
|
||||
sMap[kvPairs[i]] = kvPairs[i+1]
|
||||
}
|
||||
return sMap
|
||||
}
|
||||
|
||||
// SliceToMap convert any k-v pairs slice to map[string]any
|
||||
func SliceToMap(kvPairs ...any) map[string]any {
|
||||
ln := len(kvPairs)
|
||||
// check kvPairs length must be even
|
||||
if ln == 0 || ln%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
mp := make(map[string]any, ln/2)
|
||||
for i := 0; i < ln; i += 2 {
|
||||
kStr := strutil.SafeString(kvPairs[i])
|
||||
mp[kStr] = kvPairs[i+1]
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
// SliceToTypeMap convert k-v pairs slice to map[string]T
|
||||
func SliceToTypeMap[T any](valFunc func(any) T, kvPairs ...any) map[string]T {
|
||||
ln := len(kvPairs)
|
||||
// check kvPairs length must be even
|
||||
if ln == 0 || ln%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
mp := make(map[string]T, ln/2)
|
||||
for i := 0; i < ln; i += 2 {
|
||||
kStr := strutil.SafeString(kvPairs[i])
|
||||
mp[kStr] = valFunc(kvPairs[i+1])
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
// ToAnyMap convert map[TYPE1]TYPE2 to map[string]any
|
||||
func ToAnyMap(mp any) map[string]any {
|
||||
amp, _ := TryAnyMap(mp)
|
||||
@@ -51,15 +144,23 @@ func TryAnyMap(mp any) (map[string]any, error) {
|
||||
if aMp, ok := mp.(map[string]any); ok {
|
||||
return aMp, nil
|
||||
}
|
||||
if sMp, ok := mp.(map[string]string); ok {
|
||||
anyMp := make(map[string]any, len(sMp))
|
||||
for k, v := range sMp {
|
||||
anyMp[k] = v
|
||||
}
|
||||
return anyMp, nil
|
||||
}
|
||||
|
||||
rv := reflect.Indirect(reflect.ValueOf(mp))
|
||||
if rv.Kind() != reflect.Map {
|
||||
return nil, errors.New("input is not a map value")
|
||||
return nil, errors.New("input is not a map value type")
|
||||
}
|
||||
|
||||
anyMp := make(map[string]any, rv.Len())
|
||||
for _, key := range rv.MapKeys() {
|
||||
anyMp[key.String()] = rv.MapIndex(key).Interface()
|
||||
keyStr := strutil.SafeString(key.Interface())
|
||||
anyMp[keyStr] = rv.MapIndex(key).Interface()
|
||||
}
|
||||
return anyMp, nil
|
||||
}
|
||||
@@ -125,9 +226,7 @@ func ToString(mp map[string]any) string {
|
||||
}
|
||||
|
||||
// ToString2 simple and quickly convert a map to string.
|
||||
func ToString2(mp any) string {
|
||||
return NewFormatter(mp).Format()
|
||||
}
|
||||
func ToString2(mp any) string { return NewFormatter(mp).Format() }
|
||||
|
||||
// FormatIndent format map data to string with newline and indent.
|
||||
func FormatIndent(mp any, indent string) string {
|
||||
|
||||
197
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
197
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/arrutil"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
@@ -25,37 +26,10 @@ func (d Data) IsEmpty() bool {
|
||||
return len(d) == 0
|
||||
}
|
||||
|
||||
// Value get from the data map
|
||||
func (d Data) Value(key string) (any, bool) {
|
||||
val, ok := d.GetByPath(key)
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// Get value from the data map.
|
||||
// Supports dot syntax to get deep values. eg: top.sub
|
||||
func (d Data) Get(key string) any {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetByPath get value from the data map by path. eg: top.sub
|
||||
// Supports dot syntax to get deep values.
|
||||
func (d Data) GetByPath(path string) (any, bool) {
|
||||
if val, ok := d[path]; ok {
|
||||
return val, true
|
||||
}
|
||||
|
||||
// is key path.
|
||||
if strings.ContainsRune(path, '.') {
|
||||
val, ok := GetByPath(path, d)
|
||||
if ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
//
|
||||
// endregion
|
||||
// region T: set value(s)
|
||||
//
|
||||
|
||||
// Set value to the data map
|
||||
func (d Data) Set(key string, val any) {
|
||||
@@ -65,7 +39,7 @@ func (d Data) Set(key string, val any) {
|
||||
// SetByPath sets a value in the map.
|
||||
// Supports dot syntax to set deep values.
|
||||
//
|
||||
// For example:
|
||||
// Example:
|
||||
//
|
||||
// d.SetByPath("name.first", "Mat")
|
||||
func (d Data) SetByPath(path string, value any) error {
|
||||
@@ -78,7 +52,7 @@ func (d Data) SetByPath(path string, value any) error {
|
||||
// SetByKeys sets a value in the map by path keys.
|
||||
// Supports dot syntax to set deep values.
|
||||
//
|
||||
// For example:
|
||||
// Example:
|
||||
//
|
||||
// d.SetByKeys([]string{"name", "first"}, "Mat")
|
||||
func (d Data) SetByKeys(keys []string, value any) error {
|
||||
@@ -102,6 +76,61 @@ func (d Data) SetByKeys(keys []string, value any) error {
|
||||
// return SetByKeys((*map[string]any)(d), keys, value)
|
||||
}
|
||||
|
||||
//
|
||||
// endregion
|
||||
// region T: read value(s)
|
||||
//
|
||||
|
||||
// Value get from the data map
|
||||
func (d Data) Value(key string) (any, bool) {
|
||||
val, ok := d.GetByPath(key)
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// Get value from the data map.
|
||||
// Supports dot syntax to get deep values. eg: top.sub
|
||||
func (d Data) Get(key string) any {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// One get value from the data by multi paths. will return first founded value
|
||||
func (d Data) One(keys ...string) any {
|
||||
if val, ok := d.TryOne(keys...); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TryOne get value from the data by multi paths. will return first founded value
|
||||
func (d Data) TryOne(keys ...string) (any, bool) {
|
||||
for _, path := range keys {
|
||||
if val, ok := d.GetByPath(path); ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetByPath get value from the data map by path. eg: top.sub
|
||||
// Supports dot syntax to get deep values.
|
||||
func (d Data) GetByPath(path string) (any, bool) {
|
||||
if val, ok := d[path]; ok {
|
||||
return val, true
|
||||
}
|
||||
|
||||
// is a key path.
|
||||
if strings.ContainsRune(path, '.') {
|
||||
val, ok := GetByPath(path, d)
|
||||
if ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Default get value from the data map with default value
|
||||
func (d Data) Default(key string, def any) any {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
@@ -142,10 +171,20 @@ func (d Data) Uint64(key string) uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Str value get by key
|
||||
// Str value gets by key
|
||||
func (d Data) Str(key string) string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strutil.QuietString(val)
|
||||
return strutil.SafeString(val)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// StrOne value gets by multi keys, will return first value
|
||||
func (d Data) StrOne(keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strutil.SafeString(val)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -156,45 +195,46 @@ func (d Data) Bool(key string) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch tv := val.(type) {
|
||||
case string:
|
||||
return strutil.QuietBool(tv)
|
||||
case bool:
|
||||
return tv
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return comfunc.Bool(val)
|
||||
}
|
||||
|
||||
// Strings get []string value
|
||||
func (d Data) Strings(key string) []string {
|
||||
val, ok := d.GetByPath(key)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch typVal := val.(type) {
|
||||
case string:
|
||||
return []string{typVal}
|
||||
case []string:
|
||||
return typVal
|
||||
case []any:
|
||||
return arrutil.SliceToStrings(typVal)
|
||||
default:
|
||||
return nil
|
||||
// BoolOne value gets from multi keys, return first value
|
||||
func (d Data) BoolOne(keys ...string) bool {
|
||||
for _, key := range keys {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return comfunc.Bool(val)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StrSplit get strings by split key value
|
||||
func (d Data) StrSplit(key, sep string) []string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strings.Split(strutil.QuietString(val), sep)
|
||||
// StringsOne get []string value by multi keys, return first founded value
|
||||
func (d Data) StringsOne(keys ...string) []string {
|
||||
for _, key := range keys {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return arrutil.AnyToStrings(val)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringsByStr value get by key
|
||||
// Strings get []string value by key
|
||||
func (d Data) Strings(key string) []string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return arrutil.AnyToStrings(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StrSplit get strings by split string value
|
||||
func (d Data) StrSplit(key, sep string) []string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strings.Split(strutil.SafeString(val), sep)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringsByStr value gets by key, will split string value by ","
|
||||
func (d Data) StringsByStr(key string) []string {
|
||||
return d.StrSplit(key, ",")
|
||||
}
|
||||
@@ -221,23 +261,40 @@ func (d Data) StringMap(key string) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
// Sub get sub value as new Data
|
||||
// Sub get sub value(map[string]any) as new Data
|
||||
func (d Data) Sub(key string) Data {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
if sub, ok := val.(map[string]any); ok {
|
||||
return sub
|
||||
}
|
||||
return d.toAnyMap(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnyMap get sub value as map[string]any
|
||||
func (d Data) AnyMap(key string) map[string]any {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return d.toAnyMap(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnyMap get sub value as map[string]any
|
||||
func (d Data) toAnyMap(val any) map[string]any {
|
||||
switch tv := val.(type) {
|
||||
case map[string]string:
|
||||
return ToAnyMap(tv)
|
||||
case map[string]any:
|
||||
return tv
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Slice get []any value from data map
|
||||
func (d Data) Slice(key string) ([]any, error) {
|
||||
val, ok := d.GetByPath(key)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return arrutil.AnyToSlice(val)
|
||||
}
|
||||
|
||||
|
||||
8
vendor/github.com/gookit/goutil/maputil/get.go
generated
vendored
8
vendor/github.com/gookit/goutil/maputil/get.go
generated
vendored
@@ -202,6 +202,14 @@ func TypedKeys[K comdef.SimpleType, V any](mp map[K]V) (keys []K) {
|
||||
return
|
||||
}
|
||||
|
||||
// FirstKey returns the first key of the given map.
|
||||
func FirstKey[T any](mp map[string]T) string {
|
||||
for key := range mp {
|
||||
return key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Values get all values from the given map.
|
||||
func Values(mp any) (values []any) {
|
||||
rv := reflect.Indirect(reflect.ValueOf(mp))
|
||||
|
||||
24
vendor/github.com/gookit/goutil/maputil/maputil.go
generated
vendored
24
vendor/github.com/gookit/goutil/maputil/maputil.go
generated
vendored
@@ -58,6 +58,11 @@ func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string {
|
||||
return MergeStringMap(src, dst, ignoreCase)
|
||||
}
|
||||
|
||||
// MergeStrMap simple merge two string map. merge src to dst map
|
||||
func MergeStrMap(src, dst map[string]string) map[string]string {
|
||||
return MergeStringMap(src, dst, false)
|
||||
}
|
||||
|
||||
// MergeStringMap simple merge two string map. merge src to dst map
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
|
||||
if len(src) == 0 {
|
||||
@@ -87,6 +92,25 @@ func MergeMultiSMap(mps ...map[string]string) map[string]string {
|
||||
return newMp
|
||||
}
|
||||
|
||||
// MergeL2StrMap merge multi level2 string-map data. The back map covers the front.
|
||||
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string {
|
||||
newMp := make(map[string]map[string]string)
|
||||
for _, mp := range mps {
|
||||
for k, v := range mp {
|
||||
// merge level 2 value
|
||||
if oldV, ok := newMp[k]; ok {
|
||||
for k1, v1 := range v {
|
||||
oldV[k1] = v1
|
||||
}
|
||||
newMp[k] = oldV
|
||||
} else {
|
||||
newMp[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return newMp
|
||||
}
|
||||
|
||||
// FilterSMap filter empty elem for the string map.
|
||||
func FilterSMap(sm map[string]string) map[string]string {
|
||||
for key, val := range sm {
|
||||
|
||||
6
vendor/github.com/gookit/goutil/maputil/setval.go
generated
vendored
6
vendor/github.com/gookit/goutil/maputil/setval.go
generated
vendored
@@ -171,7 +171,7 @@ func setMapByKeys(rv reflect.Value, keys []string, nv reflect.Value) (err error)
|
||||
|
||||
if isSlice {
|
||||
// key is slice index
|
||||
if strutil.IsNumeric(key) {
|
||||
if strutil.IsInt(key) {
|
||||
idx, _ = strconv.Atoi(key)
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ func setMapByKeys(rv reflect.Value, keys []string, nv reflect.Value) (err error)
|
||||
|
||||
// next key is index number.
|
||||
nxtKey := keys[i+1]
|
||||
if strutil.IsNumeric(nxtKey) {
|
||||
if strutil.IsInt(nxtKey) {
|
||||
idx, _ = strconv.Atoi(nxtKey)
|
||||
sliLen := tmpV.Len()
|
||||
wantLen := idx + 1
|
||||
@@ -275,7 +275,7 @@ func setMapByKeys(rv reflect.Value, keys []string, nv reflect.Value) (err error)
|
||||
}
|
||||
|
||||
break
|
||||
} else if isSlice && strutil.IsNumeric(key) { // (E). slice from ptr slice
|
||||
} else if isSlice && strutil.IsInt(key) { // (E). slice from ptr slice
|
||||
idx, _ = strconv.Atoi(key)
|
||||
sliLen := rv.Len()
|
||||
wantLen := idx + 1
|
||||
|
||||
61
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
61
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
@@ -5,22 +5,23 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// SMap is alias of map[string]string
|
||||
type SMap map[string]string
|
||||
// SMap and StrMap is alias of map[string]string
|
||||
type SMap = StrMap
|
||||
type StrMap map[string]string
|
||||
|
||||
// IsEmpty of the data map
|
||||
func (m SMap) IsEmpty() bool {
|
||||
func (m StrMap) IsEmpty() bool {
|
||||
return len(m) == 0
|
||||
}
|
||||
|
||||
// Has key on the data map
|
||||
func (m SMap) Has(key string) bool {
|
||||
func (m StrMap) Has(key string) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// HasValue on the data map
|
||||
func (m SMap) HasValue(val string) bool {
|
||||
func (m StrMap) HasValue(val string) bool {
|
||||
for _, v := range m {
|
||||
if v == val {
|
||||
return true
|
||||
@@ -30,25 +31,25 @@ func (m SMap) HasValue(val string) bool {
|
||||
}
|
||||
|
||||
// Load data to the map
|
||||
func (m SMap) Load(data map[string]string) {
|
||||
func (m StrMap) Load(data map[string]string) {
|
||||
for k, v := range data {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Set value to the data map
|
||||
func (m SMap) Set(key string, val any) {
|
||||
func (m StrMap) Set(key string, val any) {
|
||||
m[key] = strutil.MustString(val)
|
||||
}
|
||||
|
||||
// Value get from the data map
|
||||
func (m SMap) Value(key string) (string, bool) {
|
||||
func (m StrMap) Value(key string) (string, bool) {
|
||||
val, ok := m[key]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// Default get value by key. if not found, return defVal
|
||||
func (m SMap) Default(key, defVal string) string {
|
||||
func (m StrMap) Default(key, defVal string) string {
|
||||
if val, ok := m[key]; ok {
|
||||
return val
|
||||
}
|
||||
@@ -56,41 +57,51 @@ func (m SMap) Default(key, defVal string) string {
|
||||
}
|
||||
|
||||
// Get value by key
|
||||
func (m SMap) Get(key string) string {
|
||||
func (m StrMap) Get(key string) string {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
// Int value get
|
||||
func (m SMap) Int(key string) int {
|
||||
func (m StrMap) Int(key string) int {
|
||||
if val, ok := m[key]; ok {
|
||||
return mathutil.QuietInt(val)
|
||||
return mathutil.SafeInt(val)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Int64 value get
|
||||
func (m SMap) Int64(key string) int64 {
|
||||
func (m StrMap) Int64(key string) int64 {
|
||||
if val, ok := m[key]; ok {
|
||||
return mathutil.QuietInt64(val)
|
||||
return mathutil.SafeInt64(val)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Str value get
|
||||
func (m SMap) Str(key string) string {
|
||||
func (m StrMap) Str(key string) string {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
// StrOne get first founded value by keys
|
||||
func (m SMap) StrOne(keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if val, ok := m[key]; ok {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Bool value get
|
||||
func (m SMap) Bool(key string) bool {
|
||||
func (m StrMap) Bool(key string) bool {
|
||||
if val, ok := m[key]; ok {
|
||||
return strutil.QuietBool(val)
|
||||
return strutil.SafeBool(val)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Ints value to []int
|
||||
func (m SMap) Ints(key string) []int {
|
||||
func (m StrMap) Ints(key string) []int {
|
||||
if val, ok := m[key]; ok {
|
||||
return strutil.Ints(val, ValSepStr)
|
||||
}
|
||||
@@ -98,7 +109,7 @@ func (m SMap) Ints(key string) []int {
|
||||
}
|
||||
|
||||
// Strings value to []string
|
||||
func (m SMap) Strings(key string) (ss []string) {
|
||||
func (m StrMap) Strings(key string) (ss []string) {
|
||||
if val, ok := m[key]; ok {
|
||||
return strutil.ToSlice(val, ValSepStr)
|
||||
}
|
||||
@@ -106,21 +117,21 @@ func (m SMap) Strings(key string) (ss []string) {
|
||||
}
|
||||
|
||||
// IfExist key, then call the fn with value.
|
||||
func (m SMap) IfExist(key string, fn func(val string)) {
|
||||
func (m StrMap) IfExist(key string, fn func(val string)) {
|
||||
if val, ok := m[key]; ok {
|
||||
fn(val)
|
||||
}
|
||||
}
|
||||
|
||||
// IfValid value is not empty, then call the fn
|
||||
func (m SMap) IfValid(key string, fn func(val string)) {
|
||||
func (m StrMap) IfValid(key string, fn func(val string)) {
|
||||
if val, ok := m[key]; ok && val != "" {
|
||||
fn(val)
|
||||
}
|
||||
}
|
||||
|
||||
// Keys of the string-map
|
||||
func (m SMap) Keys() []string {
|
||||
func (m StrMap) Keys() []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
@@ -129,7 +140,7 @@ func (m SMap) Keys() []string {
|
||||
}
|
||||
|
||||
// Values of the string-map
|
||||
func (m SMap) Values() []string {
|
||||
func (m StrMap) Values() []string {
|
||||
ss := make([]string, 0, len(m))
|
||||
for _, v := range m {
|
||||
ss = append(ss, v)
|
||||
@@ -138,7 +149,7 @@ func (m SMap) Values() []string {
|
||||
}
|
||||
|
||||
// ToKVPairs slice convert. eg: {k1:v1,k2:v2} => {k1,v1,k2,v2}
|
||||
func (m SMap) ToKVPairs() []string {
|
||||
func (m StrMap) ToKVPairs() []string {
|
||||
pairs := make([]string, 0, len(m)*2)
|
||||
for k, v := range m {
|
||||
pairs = append(pairs, k, v)
|
||||
@@ -147,6 +158,6 @@ func (m SMap) ToKVPairs() []string {
|
||||
}
|
||||
|
||||
// String data to string
|
||||
func (m SMap) String() string {
|
||||
func (m StrMap) String() string {
|
||||
return ToString2(m)
|
||||
}
|
||||
|
||||
51
vendor/github.com/gookit/goutil/maputil/smap_l2.go
generated
vendored
Normal file
51
vendor/github.com/gookit/goutil/maputil/smap_l2.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package maputil
|
||||
|
||||
import "github.com/gookit/goutil/strutil"
|
||||
|
||||
// L2StrMap is alias of map[string]map[string]string
|
||||
type L2StrMap map[string]map[string]string
|
||||
|
||||
// Load data, merge new data to old
|
||||
func (m L2StrMap) Load(mp map[string]map[string]string) {
|
||||
for k, v := range mp {
|
||||
if oldV, ok := m[k]; ok {
|
||||
for k1, v1 := range v {
|
||||
oldV[k1] = v1
|
||||
}
|
||||
m[k] = oldV
|
||||
} else {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Value get by key path. eg: "top.sub"
|
||||
func (m L2StrMap) Value(key string) (val string, ok bool) {
|
||||
top, sub, found := strutil.Cut(key, KeySepStr)
|
||||
if !found {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if vals, ok1 := m[top]; ok1 {
|
||||
val, ok = vals[sub]
|
||||
return
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Get value by key path. eg: "top.sub"
|
||||
func (m L2StrMap) Get(key string) string {
|
||||
val, _ := m.Value(key)
|
||||
return val
|
||||
}
|
||||
|
||||
// Exists check key path exists. eg: "top.sub"
|
||||
func (m L2StrMap) Exists(key string) bool {
|
||||
_, ok := m.Value(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
// StrMap get by top key. eg: "top"
|
||||
func (m L2StrMap) StrMap(top string) StrMap {
|
||||
return m[top]
|
||||
}
|
||||
6
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
6
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
@@ -56,7 +56,7 @@ func CompFloat[T comdef.Float](first, second T, op string) (ok bool) {
|
||||
}
|
||||
|
||||
// CompValue compare intX,uintX,floatX value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) {
|
||||
func CompValue[T comdef.Number](first, second T, op string) (ok bool) {
|
||||
switch op {
|
||||
case "<", "lt":
|
||||
ok = first < second
|
||||
@@ -75,12 +75,12 @@ func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) {
|
||||
}
|
||||
|
||||
// InRange check if val in int/float range [min, max]
|
||||
func InRange[T comdef.IntOrFloat](val, min, max T) bool {
|
||||
func InRange[T comdef.Number](val, min, max T) bool {
|
||||
return val >= min && val <= max
|
||||
}
|
||||
|
||||
// OutRange check if val not in int/float range [min, max]
|
||||
func OutRange[T comdef.IntOrFloat](val, min, max T) bool {
|
||||
func OutRange[T comdef.Number](val, min, max T) bool {
|
||||
return val < min || val > max
|
||||
}
|
||||
|
||||
|
||||
8
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
8
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
// Min compare two value and return max value
|
||||
func Min[T comdef.XintOrFloat](x, y T) T {
|
||||
func Min[T comdef.Number](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
@@ -15,7 +15,7 @@ func Min[T comdef.XintOrFloat](x, y T) T {
|
||||
}
|
||||
|
||||
// Max compare two value and return max value
|
||||
func Max[T comdef.XintOrFloat](x, y T) T {
|
||||
func Max[T comdef.Number](x, y T) T {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func Max[T comdef.XintOrFloat](x, y T) T {
|
||||
}
|
||||
|
||||
// SwapMin compare and always return [min, max] value
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
func SwapMin[T comdef.Number](x, y T) (T, T) {
|
||||
if x < y {
|
||||
return x, y
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
}
|
||||
|
||||
// SwapMax compare and always return [max, min] value
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
func SwapMax[T comdef.Number](x, y T) (T, T) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
|
||||
22
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
22
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
@@ -8,12 +8,12 @@ import (
|
||||
)
|
||||
|
||||
// OrElse return default value on val is zero, else return val
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T {
|
||||
func OrElse[T comdef.Number](val, defVal T) T {
|
||||
return ZeroOr(val, defVal)
|
||||
}
|
||||
|
||||
// ZeroOr return default value on val is zero, else return val
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T {
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T {
|
||||
if val != 0 {
|
||||
return val
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func ZeroOr[T comdef.XintOrFloat](val, defVal T) T {
|
||||
// LessOr(11, 10, 1) // 1
|
||||
// LessOr(2, 10, 1) // 2
|
||||
// LessOr(10, 10, 1) // 1
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
func LessOr[T comdef.Number](val, max, devVal T) T {
|
||||
if val < max {
|
||||
return val
|
||||
}
|
||||
@@ -41,7 +41,7 @@ func LessOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
// LteOr(11, 10, 1) // 11
|
||||
// LteOr(2, 10, 1) // 2
|
||||
// LteOr(10, 10, 1) // 10
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
func LteOr[T comdef.Number](val, max, devVal T) T {
|
||||
if val <= max {
|
||||
return val
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func LteOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
//
|
||||
// GreaterOr(23, 0, 2) // 23
|
||||
// GreaterOr(0, 0, 2) // 2
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T {
|
||||
func GreaterOr[T comdef.Number](val, min, defVal T) T {
|
||||
if val > min {
|
||||
return val
|
||||
}
|
||||
@@ -67,15 +67,15 @@ func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T {
|
||||
//
|
||||
// GteOr(23, 0, 2) // 23
|
||||
// GteOr(0, 0, 2) // 0
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T {
|
||||
func GteOr[T comdef.Number](val, min, defVal T) T {
|
||||
if val >= min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// Mul computes the a*b value, rounding the result.
|
||||
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64 {
|
||||
// Mul computes the `a*b` value, rounding the result.
|
||||
func Mul[T1, T2 comdef.Number](a T1, b T2) float64 {
|
||||
return math.Round(SafeFloat(a) * SafeFloat(b))
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ func MulF2i(a, b float64) int {
|
||||
return int(math.Round(a * b))
|
||||
}
|
||||
|
||||
// Div computes the a/b value, result use round handle.
|
||||
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64 {
|
||||
// Div computes the `a/b` value, result uses a round handle.
|
||||
func Div[T1, T2 comdef.Number](a T1, b T2) float64 {
|
||||
return math.Round(SafeFloat(a) / SafeFloat(b))
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func DivF2i(a, b float64) int {
|
||||
return int(math.Round(a / b))
|
||||
}
|
||||
|
||||
// Percent returns a values percent of the total
|
||||
// Percent returns a value percentage of the total
|
||||
func Percent(val, total int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
|
||||
29
vendor/github.com/gookit/goutil/reflects/check.go
generated
vendored
29
vendor/github.com/gookit/goutil/reflects/check.go
generated
vendored
@@ -5,6 +5,24 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// IsTimeType check is or alias of time.Time type
|
||||
func IsTimeType(t reflect.Type) bool {
|
||||
if t == nil || t.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
// t == timeType - 无法判断自定义类型
|
||||
return t == timeType || t.ConvertibleTo(timeType)
|
||||
}
|
||||
|
||||
// IsDurationType check is or alias of time.Duration type
|
||||
func IsDurationType(t reflect.Type) bool {
|
||||
if t == nil || t.Kind() != reflect.Int64 {
|
||||
return false
|
||||
}
|
||||
// t == durationType - 无法判断自定义类型
|
||||
return t == durationType || t.ConvertibleTo(durationType)
|
||||
}
|
||||
|
||||
// HasChild type check. eg: array, slice, map, struct
|
||||
func HasChild(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
@@ -15,7 +33,7 @@ func HasChild(v reflect.Value) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// IsArrayOrSlice check. eg: array, slice
|
||||
// IsArrayOrSlice type check. eg: array, slice
|
||||
func IsArrayOrSlice(k reflect.Kind) bool {
|
||||
return k == reflect.Slice || k == reflect.Array
|
||||
}
|
||||
@@ -70,8 +88,9 @@ func CanBeNil(typ reflect.Type) bool {
|
||||
return true
|
||||
case reflect.Struct:
|
||||
return typ == reflectValueType
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFunc value
|
||||
@@ -84,7 +103,7 @@ func IsFunc(val any) bool {
|
||||
|
||||
// IsEqual determines if two objects are considered equal.
|
||||
//
|
||||
// TIP: cannot compare function type
|
||||
// TIP: cannot compare a function type
|
||||
func IsEqual(src, dst any) bool {
|
||||
if src == nil || dst == nil {
|
||||
return src == dst
|
||||
@@ -109,7 +128,7 @@ func IsEqual(src, dst any) bool {
|
||||
// IsZero reflect value check, alias of the IsEmpty()
|
||||
var IsZero = IsEmpty
|
||||
|
||||
// IsEmpty reflect value check
|
||||
// IsEmpty reflect value check. if is ptr, check if is nil
|
||||
func IsEmpty(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
@@ -140,7 +159,7 @@ var IsEmptyValue = IsEmptyReal
|
||||
//
|
||||
// Note:
|
||||
//
|
||||
// Difference the IsEmpty(), if value is ptr or interface, will check real elem.
|
||||
// Difference the IsEmpty(), if value is ptr or interface, will check real elem.
|
||||
//
|
||||
// From src/pkg/encoding/json/encode.go.
|
||||
func IsEmptyReal(v reflect.Value) bool {
|
||||
|
||||
67
vendor/github.com/gookit/goutil/reflects/conv.go
generated
vendored
67
vendor/github.com/gookit/goutil/reflects/conv.go
generated
vendored
@@ -50,44 +50,47 @@ func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) {
|
||||
|
||||
// ValueByType create reflect.Value by give reflect.Type
|
||||
func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) {
|
||||
// handle kind: string, bool, intX, uintX, floatX
|
||||
if typ.Kind() == reflect.String || typ.Kind() <= reflect.Float64 {
|
||||
return ConvToKind(val, typ.Kind())
|
||||
}
|
||||
|
||||
var ok bool
|
||||
var newRv reflect.Value
|
||||
if newRv, ok = val.(reflect.Value); !ok {
|
||||
newRv = reflect.ValueOf(val)
|
||||
}
|
||||
|
||||
// try auto convert slice type
|
||||
if IsArrayOrSlice(newRv.Kind()) && IsArrayOrSlice(typ.Kind()) {
|
||||
return ConvSlice(newRv, typ.Elem())
|
||||
// fix: check newRv is valid
|
||||
if !newRv.IsValid() {
|
||||
return rv, comdef.ErrConvType
|
||||
}
|
||||
|
||||
// check type. like map
|
||||
// check the same type. like map
|
||||
if newRv.Type() == typ {
|
||||
return newRv, nil
|
||||
}
|
||||
|
||||
// handle kind: string, bool, intX, uintX, floatX
|
||||
if typ.Kind() == reflect.String || typ.Kind() <= reflect.Float64 {
|
||||
return ConvToKind(val, typ.Kind())
|
||||
}
|
||||
|
||||
// try the auto convert slice type
|
||||
if IsArrayOrSlice(newRv.Kind()) && IsArrayOrSlice(typ.Kind()) {
|
||||
return ConvSlice(newRv, typ.Elem())
|
||||
}
|
||||
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
// ValueByKind convert and create reflect.Value by give reflect.Kind
|
||||
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
return ConvToKind(val, kind)
|
||||
}
|
||||
func ValueByKind(val any, kind reflect.Kind) (reflect.Value, error) { return ConvToKind(val, kind) }
|
||||
|
||||
// ConvToKind convert and create reflect.Value by give reflect.Kind
|
||||
//
|
||||
// TIPs:
|
||||
//
|
||||
// Only support kind: string, bool, intX, uintX, floatX
|
||||
func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
if rv, ok := val.(reflect.Value); ok {
|
||||
val = rv.Interface()
|
||||
func ConvToKind(val any, kind reflect.Kind, fallback ...ConvFunc) (rv reflect.Value, err error) {
|
||||
if rv1, ok := val.(reflect.Value); ok {
|
||||
val = rv1.Interface()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
@@ -185,6 +188,12 @@ func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
err = err1
|
||||
}
|
||||
default:
|
||||
// call fallback func
|
||||
if len(fallback) > 0 && fallback[0] != nil {
|
||||
rv, err = fallback[0](val, kind)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
return
|
||||
@@ -254,3 +263,31 @@ func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ToTimeOrDuration convert string to time.Time or time.Duration type
|
||||
//
|
||||
// If the target type is not match, return the input string.
|
||||
func ToTimeOrDuration(str string, typ reflect.Type) (any, error) {
|
||||
// datetime, time, duration string should not greater than 64
|
||||
if len(str) > 64 {
|
||||
return str, nil
|
||||
}
|
||||
var anyVal any = str
|
||||
|
||||
// time.Time date string
|
||||
if len(str) > 5 && IsTimeType(typ) {
|
||||
ttVal, err := strutil.ToTime(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
anyVal = ttVal
|
||||
} else if IsDurationType(typ) {
|
||||
dVal, err := strutil.ToDuration(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
anyVal = dVal
|
||||
}
|
||||
|
||||
return anyVal, nil
|
||||
}
|
||||
|
||||
4
vendor/github.com/gookit/goutil/reflects/func.go
generated
vendored
4
vendor/github.com/gookit/goutil/reflects/func.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// FuncX wrap a go func. represent a function
|
||||
@@ -86,7 +86,7 @@ func (f *FuncX) Call(args ...any) ([]any, error) {
|
||||
// The function must return 1 result, or 2 results, the second of which is an error.
|
||||
//
|
||||
// - Only support func with 1 or 2 return values: (val) OR (val, err)
|
||||
// - Will check args and try convert input args to func args type.
|
||||
// - Will check args and try to convert input args to func args type.
|
||||
func (f *FuncX) Call2(args ...any) (any, error) {
|
||||
// convert args to []reflect.Value
|
||||
argRvs := make([]reflect.Value, len(args))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user