diff --git a/go.mod b/go.mod
index 40a82d6a..8185c980 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,14 @@
module github.com/DelineaXPM/terraform-provider-dsv/v2
require (
- github.com/DelineaXPM/dsv-sdk-go/v2 v2.0.1-0.20220719195420-2376a5c350ab
- github.com/magefile/mage v1.14.0
- github.com/pterm/pterm v0.12.56
- github.com/sheldonhull/magetools v1.0.0
+ github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.0
+ github.com/magefile/mage v1.15.0
+ github.com/pterm/pterm v0.12.76
+ github.com/sheldonhull/magetools v1.0.1
)
require (
+ atomicgo.dev/schedule v0.1.0 // indirect
cloud.google.com/go/compute v1.19.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
@@ -26,12 +27,12 @@ require (
github.com/vmihailenco/tagparser v0.1.2 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/protobuf v1.30.0 // indirect
+ mvdan.cc/sh/v3 v3.6.0 // indirect
)
require (
- atomicgo.dev/cursor v0.1.1 // indirect
+ atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
- bitbucket.org/creachadair/shell v0.0.7 // indirect
cloud.google.com/go v0.110.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-cidr v1.1.0 // indirect
@@ -39,15 +40,15 @@ require (
github.com/aws/aws-sdk-go v1.44.122 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
- github.com/bitfield/script v0.20.2 // indirect
+ github.com/bitfield/script v0.22.0 // indirect
github.com/containerd/console v1.0.3 // indirect
- github.com/dustin/go-humanize v1.0.0 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.7.1 // indirect
- github.com/gookit/color v1.5.2 // indirect
+ github.com/gookit/color v1.5.4 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.6.2 // indirect
@@ -61,15 +62,14 @@ require (
github.com/hashicorp/terraform-plugin-sdk v1.17.2
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
- github.com/itchyny/gojq v0.12.7 // indirect
- github.com/itchyny/timefmt-go v0.1.3 // indirect
+ github.com/itchyny/gojq v0.12.12 // indirect
+ github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.15.11 // indirect
- github.com/lithammer/fuzzysearch v1.1.5 // indirect
- github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
+ github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.16 // indirect
- github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/cli v1.1.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
@@ -85,14 +85,14 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zclconf/go-cty v1.11.1 // indirect
github.com/zclconf/go-cty-yaml v1.0.2 // indirect
- github.com/ztrue/tracerr v0.3.0 // indirect
+ github.com/ztrue/tracerr v0.4.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
- golang.org/x/mod v0.8.0 // indirect
+ golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.17.0 // indirect; indirect // indirect
golang.org/x/oauth2 v0.7.0 // indirect
- golang.org/x/sys v0.15.0 // indirect
- golang.org/x/term v0.15.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/api v0.114.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
@@ -100,4 +100,6 @@ require (
google.golang.org/grpc v1.56.3 // indirect
)
-go 1.19
+go 1.21
+
+toolchain go1.21.6
diff --git a/go.sum b/go.sum
index fd38d356..7f0f96d6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,11 @@
atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg=
-atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4=
-atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
+atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ=
+atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw=
+atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
-bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=
-bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U=
+atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
+atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -41,6 +42,7 @@ cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
+cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -56,8 +58,8 @@ cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5og
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DelineaXPM/dsv-sdk-go/v2 v2.0.1-0.20220719195420-2376a5c350ab h1:Oy5BHXmkh0FZii3XkzwJvvS9JiNRcBaa8GrhqfdJRyA=
-github.com/DelineaXPM/dsv-sdk-go/v2 v2.0.1-0.20220719195420-2376a5c350ab/go.mod h1:VOkrPSbAV+9cB/5vfDej87dcNpjUrcGbfAiN6Z3f9LI=
+github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.0 h1:+XXJ43iH4js8LIBr4MUGq1J09ycivNkTNhtn4mFyhY8=
+github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.0/go.mod h1:NTdQaRBIRZ/8gIzs010CS/u69aVSmqD1zbESW25y2cE=
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
@@ -66,6 +68,7 @@ github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzX
github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
+github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -108,8 +111,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitfield/script v0.20.2 h1:4DexsRtBILVMEn3EZwHbtJdDqdk43sXI8gM3F04JXgs=
-github.com/bitfield/script v0.20.2/go.mod h1:l3AZPVAtKQrL03bwh7nlNTUtgrgSWurpJSbtqspYrOA=
+github.com/bitfield/script v0.22.0 h1:LA7QHuEsXMPD52YLtxWrlqCCy+9FOpzNYfsRHC5Gsrc=
+github.com/bitfield/script v0.22.0/go.mod h1:ms4w+9B8f2/W0mbsgWDVTtl7K94bYuZc3AunnJC4Ebs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -122,11 +125,12 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -138,7 +142,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
+github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
@@ -196,8 +201,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
@@ -205,6 +208,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
+github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -216,6 +220,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -229,8 +234,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
-github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
-github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
+github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
+github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -295,10 +300,10 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
-github.com/itchyny/gojq v0.12.7 h1:hYPTpeWfrJ1OT+2j6cvBScbhl0TkdwGM4bc66onUSOQ=
-github.com/itchyny/gojq v0.12.7/go.mod h1:ZdvNHVlzPgUf8pgjnuDTmGfHA/21KoutQUJ3An/xNuw=
-github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU=
-github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
+github.com/itchyny/gojq v0.12.12 h1:x+xGI9BXqKoJQZkr95ibpe3cdrTbY8D9lonrK433rcA=
+github.com/itchyny/gojq v0.12.12/go.mod h1:j+3sVkjxwd7A7Z5jrbKibgOLn0ZfLWkV+Awxr/pyzJE=
+github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
+github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
@@ -320,11 +325,13 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
+github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -332,14 +339,12 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMrOBEp1c=
-github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q=
-github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
-github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
-github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
-github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
-github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
-github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
+github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
+github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
+github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
+github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
+github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
+github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -351,13 +356,14 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
github.com/mitchellh/cli v1.1.4 h1:qj8czE26AU4PbiaPXK5uVmMSM+V5BYsFBiM9HhGRLUA=
github.com/mitchellh/cli v1.1.4/go.mod h1:vTLESy5mRhKOs9KDp0/RATawxP1UqBmdrpVRMnpcvKQ=
@@ -389,6 +395,7 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -406,19 +413,21 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
-github.com/pterm/pterm v0.12.56 h1:3mrF0ytaltvWc32inyGD1Xw4Bpa/20gjGry2rImVIUc=
-github.com/pterm/pterm v0.12.56/go.mod h1:7rswprkyxYOse1IMh79w42jvReNHxro4z9oHfqjIdzM=
+github.com/pterm/pterm v0.12.76 h1:x1gbA2c7mJEd0PjJP3EYN04PR1DVrE3Z8sRDMP+qH6g=
+github.com/pterm/pterm v0.12.76/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/sheldonhull/magetools v1.0.0 h1:IkGv46ZShJvVMfzkgdFWW6VXigoKkzlVSN3Ir1OU8ZU=
-github.com/sheldonhull/magetools v1.0.0/go.mod h1:2NgMhFb1nyBhCiP4lljJ54osHHChyxyi4FBO/dWGA28=
+github.com/sheldonhull/magetools v1.0.1 h1:EzTRk0JUNl2MijssyrA2Cx+J/7SyjcTgXQmsMccDpaI=
+github.com/sheldonhull/magetools v1.0.1/go.mod h1:K5W5pCBkaBlDqnheO2mSWZ8s9t8IOsKehxvj70g8kpg=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -444,8 +453,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
@@ -463,6 +473,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
@@ -473,8 +484,8 @@ github.com/zclconf/go-cty v1.11.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeW
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0=
github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
-github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y=
-github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww=
+github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04=
+github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -494,6 +505,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
@@ -508,6 +520,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
+golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -531,8 +544,10 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -570,6 +585,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -593,6 +610,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -640,19 +659,24 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -661,6 +685,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -714,6 +740,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -849,6 +877,9 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
+mvdan.cc/sh/v3 v3.6.0 h1:gtva4EXJ0dFNvl5bHjcUEvws+KRcDslT8VKheTYkbGU=
+mvdan.cc/sh/v3 v3.6.0/go.mod h1:U4mhtBLZ32iWhif5/lD+ygy1zrgaQhUu+XFy7C8+TTA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/vendor/atomicgo.dev/cursor/.golangci.yml b/vendor/atomicgo.dev/cursor/.golangci.yml
index d18a485d..796ca35c 100644
--- a/vendor/atomicgo.dev/cursor/.golangci.yml
+++ b/vendor/atomicgo.dev/cursor/.golangci.yml
@@ -17,55 +17,83 @@ linters-settings:
- ptrToRefParam
- paramTypeCombine
- unnamedResult
- misspell:
- locale: US
linters:
disable-all: true
enable:
+ # default linters
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
+ - typecheck
+ - unused
+ # additional linters
+ - asasalint
- asciicheck
+ - bidichk
- bodyclose
+ - containedctx
+ - contextcheck
+ - decorder
- dupl
- durationcheck
+ - errchkjson
+ - errname
- errorlint
- exhaustive
- - gci
- - gocognit
+ - exhaustruct
+ - exportloopref
+ - forcetypeassert
+ - gocheckcompilerdirectives
- gocritic
- godot
- godox
- goerr113
- gofmt
- - goimports
- goprintffuncname
- - misspell
+ - gosec
+ - gosmopolitan
+ - importas
+ - ireturn
+ - nakedret
+ - nestif
- nilerr
- - nlreturn
- - noctx
+ - nilnil
- prealloc
- predeclared
+ - revive
+ - rowserrcheck
+ - tagalign
+ - tenv
- thelper
+ - tparallel
- unconvert
- unparam
+ - usestdlibvars
- wastedassign
+ - whitespace
- wrapcheck
+ - wsl
+ - gocyclo
+ - misspell
issues:
- # Excluding configuration per-path, per-linter, per-text and per-source
+ include:
+ - EXC0012
+ - EXC0014
exclude-rules:
- path: _test\.go
linters:
+ - gocyclo
- errcheck
- dupl
+ - gosec
- gocritic
- - wrapcheck
- - goerr113
- # https://github.com/go-critic/go-critic/issues/926
- linters:
- gocritic
text: "unnecessaryDefer:"
+ - linters:
+ - gocritic
+ text: "preferDecodeRune:"
service:
- golangci-lint-version: 1.39.x # use the fixed version to not introduce new linters unexpectedly
+ golangci-lint-version: 1.53.x
diff --git a/vendor/atomicgo.dev/cursor/README.md b/vendor/atomicgo.dev/cursor/README.md
index c9d6d60d..0f799745 100644
--- a/vendor/atomicgo.dev/cursor/README.md
+++ b/vendor/atomicgo.dev/cursor/README.md
@@ -1,13 +1,14 @@
AtomicGo | cursor
+
-
+
@@ -18,21 +19,19 @@
-
-
-
-
+
+
+
+
---
-Get The Module
-|
Documentation
|
Contributing
@@ -49,11 +48,6 @@
-
-
- -----------------------------------------------------------------------------------------------------
-
- |
@@ -61,214 +55,542 @@
-
-
- -----------------------------------------------------------------------------------------------------
-
- |
-## Description
+
-Package cursor contains cross-platform methods to move the terminal cursor in
-different directions. This package can be used to create interactive CLI tools
-and games, live charts, algorithm visualizations and other updatable output of
-any kind.
+
-Works niceley with https://github.com/atomicgo/keyboard
+# cursor
-Special thanks to github.com/k0kubun/go-ansi which this project is based on.
+```go
+import "atomicgo.dev/cursor"
+```
+Package cursor contains cross\-platform methods to move the terminal cursor in different directions. This package can be used to create interactive CLI tools and games, live charts, algorithm visualizations and other updatable output of any kind.
-## Usage
+Works niceley with https://github.com/atomicgo/keyboard
-#### func Bottom
+Special thanks to github.com/k0kubun/go\-ansi which this project is based on.
+
+## Index
+
+- [func Bottom\(\)](<#Bottom>)
+- [func Clear\(\)](<#Clear>)
+- [func ClearLine\(\)](<#ClearLine>)
+- [func ClearLinesDown\(n int\)](<#ClearLinesDown>)
+- [func ClearLinesUp\(n int\)](<#ClearLinesUp>)
+- [func Down\(n int\)](<#Down>)
+- [func DownAndClear\(n int\)](<#DownAndClear>)
+- [func Hide\(\)](<#Hide>)
+- [func HorizontalAbsolute\(n int\)](<#HorizontalAbsolute>)
+- [func Left\(n int\)](<#Left>)
+- [func Move\(x, y int\)](<#Move>)
+- [func Right\(n int\)](<#Right>)
+- [func SetTarget\(w Writer\)](<#SetTarget>)
+- [func Show\(\)](<#Show>)
+- [func StartOfLine\(\)](<#StartOfLine>)
+- [func StartOfLineDown\(n int\)](<#StartOfLineDown>)
+- [func StartOfLineUp\(n int\)](<#StartOfLineUp>)
+- [func TestCustomIOWriter\(t \*testing.T\)](<#TestCustomIOWriter>)
+- [func Up\(n int\)](<#Up>)
+- [func UpAndClear\(n int\)](<#UpAndClear>)
+- [type Area](<#Area>)
+ - [func NewArea\(\) Area](<#NewArea>)
+ - [func \(area \*Area\) Bottom\(\)](<#Area.Bottom>)
+ - [func \(area \*Area\) Clear\(\)](<#Area.Clear>)
+ - [func \(area \*Area\) ClearLinesDown\(n int\)](<#Area.ClearLinesDown>)
+ - [func \(area \*Area\) ClearLinesUp\(n int\)](<#Area.ClearLinesUp>)
+ - [func \(area \*Area\) Down\(n int\)](<#Area.Down>)
+ - [func \(area \*Area\) DownAndClear\(n int\)](<#Area.DownAndClear>)
+ - [func \(area \*Area\) Move\(x, y int\)](<#Area.Move>)
+ - [func \(area \*Area\) StartOfLine\(\)](<#Area.StartOfLine>)
+ - [func \(area \*Area\) StartOfLineDown\(n int\)](<#Area.StartOfLineDown>)
+ - [func \(area \*Area\) StartOfLineUp\(n int\)](<#Area.StartOfLineUp>)
+ - [func \(area \*Area\) Top\(\)](<#Area.Top>)
+ - [func \(area \*Area\) Up\(n int\)](<#Area.Up>)
+ - [func \(area \*Area\) UpAndClear\(n int\)](<#Area.UpAndClear>)
+ - [func \(area \*Area\) Update\(content string\)](<#Area.Update>)
+ - [func \(area Area\) WithWriter\(writer Writer\) Area](<#Area.WithWriter>)
+- [type Cursor](<#Cursor>)
+ - [func NewCursor\(\) \*Cursor](<#NewCursor>)
+ - [func \(c \*Cursor\) Clear\(\)](<#Cursor.Clear>)
+ - [func \(c \*Cursor\) ClearLine\(\)](<#Cursor.ClearLine>)
+ - [func \(c \*Cursor\) Down\(n int\)](<#Cursor.Down>)
+ - [func \(c \*Cursor\) Hide\(\)](<#Cursor.Hide>)
+ - [func \(c \*Cursor\) HorizontalAbsolute\(n int\)](<#Cursor.HorizontalAbsolute>)
+ - [func \(c \*Cursor\) Left\(n int\)](<#Cursor.Left>)
+ - [func \(c \*Cursor\) Right\(n int\)](<#Cursor.Right>)
+ - [func \(c \*Cursor\) Show\(\)](<#Cursor.Show>)
+ - [func \(c \*Cursor\) Up\(n int\)](<#Cursor.Up>)
+ - [func \(c \*Cursor\) WithWriter\(w Writer\) \*Cursor](<#Cursor.WithWriter>)
+- [type Writer](<#Writer>)
+
+
+
+## func [Bottom]()
```go
func Bottom()
```
-Bottom moves the cursor to the bottom of the terminal. This is done by
-calculating how many lines were moved by Up and Down.
-#### func ClearLine
+Bottom moves the cursor to the bottom of the terminal. This is done by calculating how many lines were moved by Up and Down.
+
+
+## func [Clear]()
+
+```go
+func Clear()
+```
+
+Clear clears the current position and moves the cursor to the left.
+
+
+## func [ClearLine]()
```go
func ClearLine()
```
+
ClearLine clears the current line and moves the cursor to it's start position.
-#### func ClearLinesDown
+
+## func [ClearLinesDown]()
```go
func ClearLinesDown(n int)
```
-ClearLinesDown clears n lines downwards from the current position and moves the
-cursor.
-#### func ClearLinesUp
+ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+
+
+## func [ClearLinesUp]()
```go
func ClearLinesUp(n int)
```
-ClearLinesUp clears n lines upwards from the current position and moves the
-cursor.
-#### func Down
+ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+
+
+## func [Down]()
```go
func Down(n int)
```
+
Down moves the cursor n lines down relative to the current position.
-#### func DownAndClear
+
+## func [DownAndClear]()
```go
func DownAndClear(n int)
```
+
DownAndClear moves the cursor down by n lines, then clears the line.
-#### func Hide
+
+## func [Hide]()
```go
func Hide()
```
-Hide the cursor. Don't forget to show the cursor at least at the end of your
-application with Show. Otherwise the user might have a terminal with a
-permanently hidden cursor, until he reopens the terminal.
-#### func HorizontalAbsolute
+Hide the cursor. Don't forget to show the cursor at least at the end of your application with Show. Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+
+
+## func [HorizontalAbsolute]()
```go
func HorizontalAbsolute(n int)
```
-HorizontalAbsolute moves the cursor to n horizontally. The position n is
-absolute to the start of the line.
-#### func Left
+HorizontalAbsolute moves the cursor to n horizontally. The position n is absolute to the start of the line.
+
+
+## func [Left]()
```go
func Left(n int)
```
+
Left moves the cursor n characters to the left relative to the current position.
-#### func Move
+
+## func [Move]()
```go
func Move(x, y int)
```
+
Move moves the cursor relative by x and y.
-#### func Right
+
+## func [Right]()
```go
func Right(n int)
```
-Right moves the cursor n characters to the right relative to the current
-position.
-#### func SetTarget
+Right moves the cursor n characters to the right relative to the current position.
+
+
+## func [SetTarget]()
```go
func SetTarget(w Writer)
```
-SetTarget allows for any arbitrary Writer to be used
-#### func Show
+SetTarget sets to output target of the default curser to the provided cursor.Writer \(wrapping io.Writer\).
+
+
+## func [Show]()
```go
func Show()
```
-Show the cursor if it was hidden previously. Don't forget to show the cursor at
-least at the end of your application. Otherwise the user might have a terminal
-with a permanently hidden cursor, until he reopens the terminal.
-#### func StartOfLine
+Show the cursor if it was hidden previously. Don't forget to show the cursor at least at the end of your application. Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+
+
+## func [StartOfLine]()
```go
func StartOfLine()
```
+
StartOfLine moves the cursor to the start of the current line.
-#### func StartOfLineDown
+
+## func [StartOfLineDown]()
```go
func StartOfLineDown(n int)
```
-StartOfLineDown moves the cursor down by n lines, then moves to cursor to the
-start of the line.
-#### func StartOfLineUp
+StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+
+
+## func [StartOfLineUp]()
```go
func StartOfLineUp(n int)
```
-StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start
-of the line.
-#### func TestCustomIOWriter
+StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+
+
+## func [TestCustomIOWriter]()
```go
func TestCustomIOWriter(t *testing.T)
```
-#### func Up
+TestCustomIOWriter tests the cursor functions with a custom Writer.
+
+
+## func [Up]()
```go
func Up(n int)
```
+
Up moves the cursor n lines up relative to the current position.
-#### func UpAndClear
+
+## func [UpAndClear]()
```go
func UpAndClear(n int)
```
+
UpAndClear moves the cursor up by n lines, then clears the line.
-#### type Area
+
+## type [Area]()
+
+Area displays content which can be updated on the fly. You can use this to create live output, charts, dropdowns, etc.
```go
type Area struct {
+ // contains filtered or unexported fields
}
```
-Area displays content which can be updated on the fly. You can use this to
-create live output, charts, dropdowns, etc.
-
-#### func NewArea
+
+### func [NewArea]()
```go
func NewArea() Area
```
+
NewArea returns a new Area.
-#### func (*Area) Clear
+
+### func \(\*Area\) [Bottom]()
+
+```go
+func (area *Area) Bottom()
+```
+
+Bottom moves the cursor to the bottom of the terminal. This is done by calculating how many lines were moved by Up and Down.
+
+
+### func \(\*Area\) [Clear]()
```go
func (area *Area) Clear()
```
+
Clear clears the content of the Area.
-#### func (*Area) Update
+
+### func \(\*Area\) [ClearLinesDown]()
+
+```go
+func (area *Area) ClearLinesDown(n int)
+```
+
+ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+
+
+### func \(\*Area\) [ClearLinesUp]()
+
+```go
+func (area *Area) ClearLinesUp(n int)
+```
+
+ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+
+
+### func \(\*Area\) [Down]()
+
+```go
+func (area *Area) Down(n int)
+```
+
+Down moves the cursor of the area down one line.
+
+
+### func \(\*Area\) [DownAndClear]()
+
+```go
+func (area *Area) DownAndClear(n int)
+```
+
+DownAndClear moves the cursor down by n lines, then clears the line.
+
+
+### func \(\*Area\) [Move]()
+
+```go
+func (area *Area) Move(x, y int)
+```
+
+Move moves the cursor relative by x and y.
+
+
+### func \(\*Area\) [StartOfLine]()
+
+```go
+func (area *Area) StartOfLine()
+```
+
+StartOfLine moves the cursor to the start of the current line.
+
+
+### func \(\*Area\) [StartOfLineDown]()
+
+```go
+func (area *Area) StartOfLineDown(n int)
+```
+
+StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+
+
+### func \(\*Area\) [StartOfLineUp]()
+
+```go
+func (area *Area) StartOfLineUp(n int)
+```
+
+StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+
+
+### func \(\*Area\) [Top]()
+
+```go
+func (area *Area) Top()
+```
+
+Top moves the cursor to the top of the area. This is done by calculating how many lines were moved by Up and Down.
+
+
+### func \(\*Area\) [Up]()
+
+```go
+func (area *Area) Up(n int)
+```
+
+Up moves the cursor of the area up one line.
+
+
+### func \(\*Area\) [UpAndClear]()
+
+```go
+func (area *Area) UpAndClear(n int)
+```
+
+UpAndClear moves the cursor up by n lines, then clears the line.
+
+
+### func \(\*Area\) [Update]()
```go
func (area *Area) Update(content string)
```
-Update overwrites the content of the Area.
-#### type Writer
+Update overwrites the content of the Area and adjusts its height based on content.
+
+
+### func \(Area\) [WithWriter]()
```go
-type Writer interface {
- io.Writer
- Fd() uintptr
+func (area Area) WithWriter(writer Writer) Area
+```
+
+WithWriter sets the custom writer.
+
+
+## type [Cursor]()
+
+Cursor displays content which can be updated on the fly. You can use this to create live output, charts, dropdowns, etc.
+
+```go
+type Cursor struct {
+ // contains filtered or unexported fields
}
```
+
+### func [NewCursor]()
+
+```go
+func NewCursor() *Cursor
+```
+
+NewCursor creates a new Cursor instance writing to os.Stdout.
+
+
+### func \(\*Cursor\) [Clear]()
+
+```go
+func (c *Cursor) Clear()
+```
+
+Clear clears the current position and moves the cursor to the left.
+
+
+### func \(\*Cursor\) [ClearLine]()
+
+```go
+func (c *Cursor) ClearLine()
+```
+
+ClearLine clears the current line and moves the cursor to it's start position.
+
+
+### func \(\*Cursor\) [Down]()
+
+```go
+func (c *Cursor) Down(n int)
+```
+
+Down moves the cursor n lines down relative to the current position.
+
+
+### func \(\*Cursor\) [Hide]()
+
+```go
+func (c *Cursor) Hide()
+```
+
+Hide the cursor. Don't forget to show the cursor at least at the end of your application with Show. Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+
+
+### func \(\*Cursor\) [HorizontalAbsolute]()
+
+```go
+func (c *Cursor) HorizontalAbsolute(n int)
+```
+
+HorizontalAbsolute moves the cursor to n horizontally. The position n is absolute to the start of the line.
+
+
+### func \(\*Cursor\) [Left]()
+
+```go
+func (c *Cursor) Left(n int)
+```
+
+Left moves the cursor n characters to the left relative to the current position.
+
+
+### func \(\*Cursor\) [Right]()
+
+```go
+func (c *Cursor) Right(n int)
+```
+
+Right moves the cursor n characters to the right relative to the current position.
+
+
+### func \(\*Cursor\) [Show]()
+
+```go
+func (c *Cursor) Show()
+```
+
+Show the cursor if it was hidden previously. Don't forget to show the cursor at least at the end of your application. Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+
+
+### func \(\*Cursor\) [Up]()
+
+```go
+func (c *Cursor) Up(n int)
+```
+
+Up moves the cursor n lines up relative to the current position.
+
+
+### func \(\*Cursor\) [WithWriter]()
+
+```go
+func (c *Cursor) WithWriter(w Writer) *Cursor
+```
+
+WithWriter allows for any arbitrary Writer to be used for cursor movement abstracted.
+
+
+## type [Writer]()
+
Writer is an expanded io.Writer interface with a file descriptor.
+```go
+type Writer interface {
+ io.Writer
+ Fd() uintptr
+}
+```
+
+Generated by [gomarkdoc]()
+
+
+
+
---
> [AtomicGo.dev](https://atomicgo.dev) ·
diff --git a/vendor/atomicgo.dev/cursor/area.go b/vendor/atomicgo.dev/cursor/area.go
index e8cd72d5..5b26b5db 100644
--- a/vendor/atomicgo.dev/cursor/area.go
+++ b/vendor/atomicgo.dev/cursor/area.go
@@ -1,49 +1,164 @@
package cursor
import (
- "fmt"
- "runtime"
+ "os"
"strings"
)
// Area displays content which can be updated on the fly.
// You can use this to create live output, charts, dropdowns, etc.
type Area struct {
- height int
+ height int
+ writer Writer
+ cursor *Cursor
+ cursorPosY int
}
// NewArea returns a new Area.
func NewArea() Area {
- return Area{}
+ return Area{
+ height: 0,
+ writer: os.Stdout,
+ cursor: cursor,
+ cursorPosY: 0,
+ }
+}
+
+// WithWriter sets the custom writer.
+func (area Area) WithWriter(writer Writer) Area {
+ area.writer = writer
+ area.cursor = area.cursor.WithWriter(writer)
+
+ return area
}
// Clear clears the content of the Area.
func (area *Area) Clear() {
- Bottom()
+ // Initialize writer if not done yet
+ if area.writer == nil {
+ area.writer = os.Stdout
+ }
+
if area.height > 0 {
- ClearLinesUp(area.height)
+ area.Bottom()
+ area.ClearLinesUp(area.height)
+ area.StartOfLine()
+ } else {
+ area.StartOfLine()
+ area.cursor.ClearLine()
}
}
-// Update overwrites the content of the Area.
+// Update overwrites the content of the Area and adjusts its height based on content.
func (area *Area) Update(content string) {
area.Clear()
- lines := strings.Split(content, "\n")
-
- fmt.Println(strings.Repeat("\n", len(lines)-1)) // This appends space if the terminal is at the bottom
- Up(len(lines))
+ area.writeArea(content)
+ area.cursorPosY = 0
+ area.height = strings.Count(content, "\n")
+}
- if runtime.GOOS == "windows" {
- for _, line := range lines {
- fmt.Print(line)
- StartOfLineDown(1)
+// Up moves the cursor of the area up one line.
+func (area *Area) Up(n int) {
+ if n > 0 {
+ if area.cursorPosY+n > area.height {
+ n = area.height - area.cursorPosY
}
- } else {
- for _, line := range lines {
- fmt.Println(line)
+
+ area.cursor.Up(n)
+ area.cursorPosY += n
+ }
+}
+
+// Down moves the cursor of the area down one line.
+func (area *Area) Down(n int) {
+ if n > 0 {
+ if area.cursorPosY-n < 0 {
+ n = area.height - area.cursorPosY
}
+
+ area.cursor.Down(n)
+ area.cursorPosY -= n
}
- height = 0
+}
+
+// Bottom moves the cursor to the bottom of the terminal.
+// This is done by calculating how many lines were moved by Up and Down.
+func (area *Area) Bottom() {
+ if area.cursorPosY > 0 {
+ area.Down(area.cursorPosY)
+ area.cursorPosY = 0
+ }
+}
+
+// Top moves the cursor to the top of the area.
+// This is done by calculating how many lines were moved by Up and Down.
+func (area *Area) Top() {
+ if area.cursorPosY < area.height {
+ area.Up(area.height - area.cursorPosY)
+ area.cursorPosY = area.height
+ }
+}
- area.height = len(lines)
+// StartOfLine moves the cursor to the start of the current line.
+func (area *Area) StartOfLine() {
+ area.cursor.HorizontalAbsolute(0)
+}
+
+// StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+func (area *Area) StartOfLineDown(n int) {
+ area.Down(n)
+ area.StartOfLine()
+}
+
+// StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+func (area *Area) StartOfLineUp(n int) {
+ area.Up(n)
+ area.StartOfLine()
+}
+
+// UpAndClear moves the cursor up by n lines, then clears the line.
+func (area *Area) UpAndClear(n int) {
+ area.Up(n)
+ area.cursor.ClearLine()
+}
+
+// DownAndClear moves the cursor down by n lines, then clears the line.
+func (area *Area) DownAndClear(n int) {
+ area.Down(n)
+ area.cursor.ClearLine()
+}
+
+// Move moves the cursor relative by x and y.
+func (area *Area) Move(x, y int) {
+ if x > 0 {
+ area.cursor.Right(x)
+ } else if x < 0 {
+ area.cursor.Left(-x)
+ }
+
+ if y > 0 {
+ area.Up(y)
+ } else if y < 0 {
+ area.Down(-y)
+ }
+}
+
+// ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+func (area *Area) ClearLinesUp(n int) {
+ area.StartOfLine()
+ area.cursor.ClearLine()
+
+ for i := 0; i < n; i++ {
+ area.UpAndClear(1)
+ }
+}
+
+// ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+func (area *Area) ClearLinesDown(n int) {
+ area.StartOfLine()
+ area.cursor.ClearLine()
+
+ for i := 0; i < n; i++ {
+ area.DownAndClear(1)
+ }
}
diff --git a/vendor/atomicgo.dev/cursor/area_other.go b/vendor/atomicgo.dev/cursor/area_other.go
new file mode 100644
index 00000000..b92390de
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/area_other.go
@@ -0,0 +1,13 @@
+//go:build !windows
+// +build !windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// Update overwrites the content of the Area and adjusts its height based on content.
+func (area *Area) writeArea(content string) {
+ fmt.Fprint(area.writer, content)
+}
diff --git a/vendor/atomicgo.dev/cursor/area_windows.go b/vendor/atomicgo.dev/cursor/area_windows.go
new file mode 100644
index 00000000..de7dd292
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/area_windows.go
@@ -0,0 +1,21 @@
+//go:build windows
+// +build windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// writeArea is a helper for platform dependant output.
+// For Windows newlines '\n' in the content are replaced by '\r\n'
+func (area *Area) writeArea(content string) {
+ last := ' '
+ for _, r := range content {
+ if r == '\n' && last != '\r' {
+ fmt.Fprint(area.writer, "\r\n")
+ continue
+ }
+ fmt.Fprint(area.writer, string(r))
+ }
+}
diff --git a/vendor/atomicgo.dev/cursor/cursor.go b/vendor/atomicgo.dev/cursor/cursor.go
index fb4c010b..89a3efcf 100644
--- a/vendor/atomicgo.dev/cursor/cursor.go
+++ b/vendor/atomicgo.dev/cursor/cursor.go
@@ -1,69 +1,26 @@
-//go:build !windows
-// +build !windows
-
package cursor
import (
- "fmt"
"os"
)
-var target Writer = os.Stdout
-
-// SetTarget allows for any arbitrary io.Writer to be used
-// for cursor movement (will not work on Windows).
-func SetTarget(w Writer) {
- target = w
+// Cursor displays content which can be updated on the fly.
+// You can use this to create live output, charts, dropdowns, etc.
+type Cursor struct {
+ writer Writer
}
-// Up moves the cursor n lines up relative to the current position.
-func Up(n int) {
- fmt.Fprintf(target, "\x1b[%dA", n)
- height += n
+// NewCursor creates a new Cursor instance writing to os.Stdout.
+func NewCursor() *Cursor {
+ return &Cursor{writer: os.Stdout}
}
-// Down moves the cursor n lines down relative to the current position.
-func Down(n int) {
- fmt.Fprintf(target, "\x1b[%dB", n)
- if height-n <= 0 {
- height = 0
- } else {
- height -= n
+// WithWriter allows for any arbitrary Writer to be used
+// for cursor movement abstracted.
+func (c *Cursor) WithWriter(w Writer) *Cursor {
+ if w != nil {
+ c.writer = w
}
-}
-
-// Right moves the cursor n characters to the right relative to the current position.
-func Right(n int) {
- fmt.Fprintf(target, "\x1b[%dC", n)
-}
-
-// Left moves the cursor n characters to the left relative to the current position.
-func Left(n int) {
- fmt.Fprintf(target, "\x1b[%dD", n)
-}
-
-// HorizontalAbsolute moves the cursor to n horizontally.
-// The position n is absolute to the start of the line.
-func HorizontalAbsolute(n int) {
- n += 1 // Moves the line to the character after n
- fmt.Fprintf(target, "\x1b[%dG", n)
-}
-
-// Show the cursor if it was hidden previously.
-// Don't forget to show the cursor at least at the end of your application.
-// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
-func Show() {
- fmt.Fprint(target, "\x1b[?25h")
-}
-
-// Hide the cursor.
-// Don't forget to show the cursor at least at the end of your application with Show.
-// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
-func Hide() {
- fmt.Fprintf(target, "\x1b[?25l")
-}
-// ClearLine clears the current line and moves the cursor to it's start position.
-func ClearLine() {
- fmt.Fprintf(target, "\x1b[2K")
+ return c
}
diff --git a/vendor/atomicgo.dev/cursor/cursor_other.go b/vendor/atomicgo.dev/cursor/cursor_other.go
new file mode 100644
index 00000000..7c185578
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/cursor_other.go
@@ -0,0 +1,67 @@
+//go:build !windows
+// +build !windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// Up moves the cursor n lines up relative to the current position.
+func (c *Cursor) Up(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dA", n)
+ }
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func (c *Cursor) Down(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dB", n)
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func (c *Cursor) Right(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dC", n)
+ }
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func (c *Cursor) Left(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dD", n)
+ }
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func (c *Cursor) HorizontalAbsolute(n int) {
+ n++ // Moves the line to the character after n
+ fmt.Fprintf(c.writer, "\x1b[%dG", n)
+}
+
+// Show the cursor if it was hidden previously.
+// Don't forget to show the cursor at least at the end of your application.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+func (c *Cursor) Show() {
+ fmt.Fprint(c.writer, "\x1b[?25h")
+}
+
+// Hide the cursor.
+// Don't forget to show the cursor at least at the end of your application with Show.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+func (c *Cursor) Hide() {
+ fmt.Fprintf(c.writer, "\x1b[?25l")
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func (c *Cursor) ClearLine() {
+ fmt.Fprintf(c.writer, "\x1b[2K")
+}
+
+// Clear clears the current position and moves the cursor to the left.
+func (c *Cursor) Clear() {
+ fmt.Fprintf(c.writer, "\x1b[K")
+}
diff --git a/vendor/atomicgo.dev/cursor/cursor_test_linux.go b/vendor/atomicgo.dev/cursor/cursor_test_linux.go
index 25179b23..6a37f406 100644
--- a/vendor/atomicgo.dev/cursor/cursor_test_linux.go
+++ b/vendor/atomicgo.dev/cursor/cursor_test_linux.go
@@ -6,75 +6,93 @@ import (
"testing"
)
+// TestCustomIOWriter tests the cursor functions with a custom Writer.
func TestCustomIOWriter(t *testing.T) {
tmpFile, err := os.CreateTemp("", "testingTmpFile-")
+ defer os.Remove(tmpFile.Name())
+
if err != nil {
log.Fatal(err)
}
- defer os.Remove(tmpFile.Name())
w := tmpFile
SetTarget(w)
Up(2)
+
expected := "\x1b[2A"
actual := getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
Down(2)
+
expected = "\x1b[2B"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
Right(2)
+
expected = "\x1b[2C"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
Left(2)
+
expected = "\x1b[2D"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
Hide()
+
expected = "\x1b[?25l"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
Show()
+
expected = "\x1b[?25h"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
ClearLine()
+
expected = "\x1b[2K"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
clearFile(t, w)
HorizontalAbsolute(3)
+
expected = "\x1b[4G"
actual = getFileContent(t, w.Name())
+
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
@@ -82,6 +100,7 @@ func TestCustomIOWriter(t *testing.T) {
func getFileContent(t *testing.T, fileName string) string {
t.Helper()
+
content, err := os.ReadFile(fileName)
if err != nil {
t.Errorf("failed to read file contents: %s", err)
@@ -94,12 +113,14 @@ func getFileContent(t *testing.T, fileName string) string {
func clearFile(t *testing.T, file *os.File) {
t.Helper()
+
err := file.Truncate(0)
if err != nil {
t.Errorf("failed to clear file")
return
}
+
_, err = file.Seek(0, 0)
if err != nil {
t.Errorf("failed to clear file")
diff --git a/vendor/atomicgo.dev/cursor/cursor_windows.go b/vendor/atomicgo.dev/cursor/cursor_windows.go
index 0a3be0af..ebe2bc59 100644
--- a/vendor/atomicgo.dev/cursor/cursor_windows.go
+++ b/vendor/atomicgo.dev/cursor/cursor_windows.go
@@ -1,46 +1,35 @@
+//go:build windows
+// +build windows
+
package cursor
import (
- "os"
"syscall"
"unsafe"
)
-var target Writer = os.Stdout
-
-// SetTarget allows for any arbitrary Writer to be used
-func SetTarget(w Writer) {
- target = w
-}
-
// Up moves the cursor n lines up relative to the current position.
-func Up(n int) {
- move(0, -n)
- height += n
+func (c *Cursor) Up(n int) {
+ c.move(0, -n)
}
// Down moves the cursor n lines down relative to the current position.
-func Down(n int) {
- move(0, n)
- if height-n <= 0 {
- height = 0
- } else {
- height -= n
- }
+func (c *Cursor) Down(n int) {
+ c.move(0, n)
}
// Right moves the cursor n characters to the right relative to the current position.
-func Right(n int) {
- move(n, 0)
+func (c *Cursor) Right(n int) {
+ c.move(n, 0)
}
// Left moves the cursor n characters to the left relative to the current position.
-func Left(n int) {
- move(-n, 0)
+func (c *Cursor) Left(n int) {
+ c.move(-n, 0)
}
-func move(x int, y int) {
- handle := syscall.Handle(target.Fd())
+func (c *Cursor) move(x int, y int) {
+ handle := syscall.Handle(c.writer.Fd())
var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
@@ -54,8 +43,8 @@ func move(x int, y int) {
// HorizontalAbsolute moves the cursor to n horizontally.
// The position n is absolute to the start of the line.
-func HorizontalAbsolute(n int) {
- handle := syscall.Handle(target.Fd())
+func (c *Cursor) HorizontalAbsolute(n int) {
+ handle := syscall.Handle(c.writer.Fd())
var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
@@ -74,8 +63,8 @@ func HorizontalAbsolute(n int) {
// Show the cursor if it was hidden previously.
// Don't forget to show the cursor at least at the end of your application.
// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
-func Show() {
- handle := syscall.Handle(target.Fd())
+func (c *Cursor) Show() {
+ handle := syscall.Handle(c.writer.Fd())
var cci consoleCursorInfo
_, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
@@ -87,8 +76,8 @@ func Show() {
// Hide the cursor.
// Don't forget to show the cursor at least at the end of your application with Show.
// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
-func Hide() {
- handle := syscall.Handle(target.Fd())
+func (c *Cursor) Hide() {
+ handle := syscall.Handle(c.writer.Fd())
var cci consoleCursorInfo
_, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
@@ -97,9 +86,9 @@ func Hide() {
_, _, _ = procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
}
-// ClearLine clears the current line and moves the cursor to it's start position.
-func ClearLine() {
- handle := syscall.Handle(target.Fd())
+// ClearLine clears the current line and moves the cursor to its start position.
+func (c *Cursor) ClearLine() {
+ handle := syscall.Handle(c.writer.Fd())
var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
@@ -110,3 +99,20 @@ func ClearLine() {
x = csbi.size.x
_, _, _ = procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
}
+
+// Clear clears the current position and moves the cursor to the left.
+func (c *Cursor) Clear() {
+ handle := syscall.Handle(c.writer.Fd())
+
+ var csbi consoleScreenBufferInfo
+ _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+
+ var w uint32
+ cursor := csbi.cursorPosition
+ _, _, _ = procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(1), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
+
+ if cursor.x > 0 {
+ cursor.x--
+ }
+ _, _, _ = procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
+}
diff --git a/vendor/atomicgo.dev/cursor/go.work b/vendor/atomicgo.dev/cursor/go.work
new file mode 100644
index 00000000..c71ff3ba
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/go.work
@@ -0,0 +1,10 @@
+go 1.18
+
+use .
+
+// replace git.neotel.at/go/c5rest => /home/rl/work/c5rest
+// replace git.neotel.at/go/c5db => /home/rl/work/c5db
+
+// replace github.com/pterm/pterm => H:/work/github.com/pterm/pterm
+
+// replace atomicgo.dev/cursor => H:/github.com/atomicgo.dev/cursor
diff --git a/vendor/atomicgo.dev/cursor/utils.go b/vendor/atomicgo.dev/cursor/utils.go
index cde36686..4b75f09e 100644
--- a/vendor/atomicgo.dev/cursor/utils.go
+++ b/vendor/atomicgo.dev/cursor/utils.go
@@ -1,16 +1,92 @@
package cursor
-import "io"
+import (
+ "io"
+ "os"
+)
-var height int
+//
+// Helpers for global cursor handling on os.Stdout
+//
+
+var autoheight int
+var cursor = &Cursor{writer: os.Stdout}
+
+// Writer is an expanded io.Writer interface with a file descriptor.
+type Writer interface {
+ io.Writer
+ Fd() uintptr
+}
+
+// SetTarget sets to output target of the default curser to the
+// provided cursor.Writer (wrapping io.Writer).
+func SetTarget(w Writer) {
+ cursor = cursor.WithWriter(w)
+}
+
+// Up moves the cursor n lines up relative to the current position.
+func Up(n int) {
+ cursor.Up(n)
+ autoheight += n
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func Down(n int) {
+ cursor.Down(n)
+
+ if autoheight > 0 {
+ autoheight -= n
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func Right(n int) {
+ cursor.Right(n)
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func Left(n int) {
+ cursor.Left(n)
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func HorizontalAbsolute(n int) {
+ cursor.HorizontalAbsolute(n)
+}
+
+// Show the cursor if it was hidden previously.
+// Don't forget to show the cursor at least at the end of your application.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+func Show() {
+ cursor.Show()
+}
+
+// Hide the cursor.
+// Don't forget to show the cursor at least at the end of your application with Show.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until they reopen the terminal.
+func Hide() {
+ cursor.Hide()
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func ClearLine() {
+ cursor.ClearLine()
+}
+
+// Clear clears the current position and moves the cursor to the left.
+func Clear() {
+ cursor.Clear()
+}
// Bottom moves the cursor to the bottom of the terminal.
// This is done by calculating how many lines were moved by Up and Down.
func Bottom() {
- if height > 0 {
- Down(height)
+ if autoheight > 0 {
+ Down(autoheight)
StartOfLine()
- height = 0
+
+ autoheight = 0
}
}
@@ -73,9 +149,3 @@ func ClearLinesDown(n int) {
DownAndClear(1)
}
}
-
-// Writer is an expanded io.Writer interface with a file descriptor.
-type Writer interface {
- io.Writer
- Fd() uintptr
-}
diff --git a/vendor/atomicgo.dev/schedule/.gitignore b/vendor/atomicgo.dev/schedule/.gitignore
new file mode 100644
index 00000000..7e5f3f45
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/.gitignore
@@ -0,0 +1,40 @@
+# Go template
+
+## Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+## Test binary, built with `go test -c`
+*.test
+
+## Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+## Dependency directories (remove the comment below to include it)
+vendor/
+
+# IDEs
+
+## IntelliJ
+.idea
+*.iml
+out
+gen
+
+## Visual Studio Code
+.vscode
+*.code-workspace
+
+# Operating System Files
+
+## macOS
+### General
+.DS_Store
+
+# Other
+
+## Experimenting folder
+experimenting
diff --git a/vendor/atomicgo.dev/schedule/.golangci.yml b/vendor/atomicgo.dev/schedule/.golangci.yml
new file mode 100644
index 00000000..796ca35c
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/.golangci.yml
@@ -0,0 +1,99 @@
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ disabled-checks:
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - whyNoLint
+ - wrapperFunc
+ - exitAfterDefer
+ - hugeParam
+ - ptrToRefParam
+ - paramTypeCombine
+ - unnamedResult
+linters:
+ disable-all: true
+ enable:
+ # default linters
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - typecheck
+ - unused
+ # additional linters
+ - asasalint
+ - asciicheck
+ - bidichk
+ - bodyclose
+ - containedctx
+ - contextcheck
+ - decorder
+ - dupl
+ - durationcheck
+ - errchkjson
+ - errname
+ - errorlint
+ - exhaustive
+ - exhaustruct
+ - exportloopref
+ - forcetypeassert
+ - gocheckcompilerdirectives
+ - gocritic
+ - godot
+ - godox
+ - goerr113
+ - gofmt
+ - goprintffuncname
+ - gosec
+ - gosmopolitan
+ - importas
+ - ireturn
+ - nakedret
+ - nestif
+ - nilerr
+ - nilnil
+ - prealloc
+ - predeclared
+ - revive
+ - rowserrcheck
+ - tagalign
+ - tenv
+ - thelper
+ - tparallel
+ - unconvert
+ - unparam
+ - usestdlibvars
+ - wastedassign
+ - whitespace
+ - wrapcheck
+ - wsl
+ - gocyclo
+ - misspell
+issues:
+ include:
+ - EXC0012
+ - EXC0014
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - gocyclo
+ - errcheck
+ - dupl
+ - gosec
+ - gocritic
+ - linters:
+ - gocritic
+ text: "unnecessaryDefer:"
+ - linters:
+ - gocritic
+ text: "preferDecodeRune:"
+service:
+ golangci-lint-version: 1.53.x
diff --git a/vendor/atomicgo.dev/schedule/LICENSE b/vendor/atomicgo.dev/schedule/LICENSE
new file mode 100644
index 00000000..b42989ef
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Marvin Wendt (MarvinJWendt)
+
+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.
diff --git a/vendor/atomicgo.dev/schedule/README.md b/vendor/atomicgo.dev/schedule/README.md
new file mode 100644
index 00000000..3f7f9a84
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/README.md
@@ -0,0 +1,281 @@
+AtomicGo | schedule
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+Documentation
+|
+Contributing
+|
+Code of Conduct
+
+
+---
+
+
+
+
+
+
+
+
+go get atomicgo.dev/schedule
+
+
+
+
+
+
+
+
+# schedule
+
+```go
+import "atomicgo.dev/schedule"
+```
+
+Package schedule provides a simple scheduler for Go.
+
+It can run a function at a given time, in a given duration, or repeatedly at a given interval.
+
+## Index
+
+- [type Task](<#Task>)
+ - [func After\(d time.Duration, task func\(\)\) \*Task](<#After>)
+ - [func At\(t time.Time, task func\(\)\) \*Task](<#At>)
+ - [func Every\(interval time.Duration, task func\(\) bool\) \*Task](<#Every>)
+ - [func \(s \*Task\) ExecutesIn\(\) time.Duration](<#Task.ExecutesIn>)
+ - [func \(s \*Task\) IsActive\(\) bool](<#Task.IsActive>)
+ - [func \(s \*Task\) NextExecutionTime\(\) time.Time](<#Task.NextExecutionTime>)
+ - [func \(s \*Task\) StartedAt\(\) time.Time](<#Task.StartedAt>)
+ - [func \(s \*Task\) Stop\(\)](<#Task.Stop>)
+ - [func \(s \*Task\) Wait\(\)](<#Task.Wait>)
+
+
+
+## type [Task]()
+
+Task holds information about the running task and can be used to stop running tasks.
+
+```go
+type Task struct {
+ // contains filtered or unexported fields
+}
+```
+
+
+### func [After]()
+
+```go
+func After(d time.Duration, task func()) *Task
+```
+
+After executes the task after the given duration. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.After(5*time.Second, func() {
+ fmt.Println("5 seconds are over!")
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ task.Wait()
+}
+```
+
+
+
+
+
+### func [At]()
+
+```go
+func At(t time.Time, task func()) *Task
+```
+
+At executes the task at the given time. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.At(time.Now().Add(5*time.Second), func() {
+ fmt.Println("5 seconds are over!")
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ task.Wait()
+}
+```
+
+
+
+
+
+### func [Every]()
+
+```go
+func Every(interval time.Duration, task func() bool) *Task
+```
+
+Every executes the task in the given interval, as long as the task function returns true. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.Every(time.Second, func() bool {
+ fmt.Println("1 second is over!")
+ return true // return false to stop the task
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ time.Sleep(10 * time.Second)
+
+ task.Stop()
+}
+```
+
+
+
+
+
+### func \(\*Task\) [ExecutesIn]()
+
+```go
+func (s *Task) ExecutesIn() time.Duration
+```
+
+ExecutesIn returns the duration until the next execution.
+
+
+### func \(\*Task\) [IsActive]()
+
+```go
+func (s *Task) IsActive() bool
+```
+
+IsActive returns true if the scheduler is active.
+
+
+### func \(\*Task\) [NextExecutionTime]()
+
+```go
+func (s *Task) NextExecutionTime() time.Time
+```
+
+NextExecutionTime returns the time when the next execution will happen.
+
+
+### func \(\*Task\) [StartedAt]()
+
+```go
+func (s *Task) StartedAt() time.Time
+```
+
+StartedAt returns the time when the scheduler was started.
+
+
+### func \(\*Task\) [Stop]()
+
+```go
+func (s *Task) Stop()
+```
+
+Stop stops the scheduler.
+
+
+### func \(\*Task\) [Wait]()
+
+```go
+func (s *Task) Wait()
+```
+
+Wait blocks until the scheduler is stopped. After and At will stop automatically after the task is executed.
+
+Generated by [gomarkdoc]()
+
+
+
+
+---
+
+> [AtomicGo.dev](https://atomicgo.dev) ·
+> with ❤️ by [@MarvinJWendt](https://github.com/MarvinJWendt) |
+> [MarvinJWendt.com](https://marvinjwendt.com)
diff --git a/vendor/atomicgo.dev/schedule/codecov.yml b/vendor/atomicgo.dev/schedule/codecov.yml
new file mode 100644
index 00000000..bfdc9877
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/codecov.yml
@@ -0,0 +1,8 @@
+coverage:
+ status:
+ project:
+ default:
+ informational: true
+ patch:
+ default:
+ informational: true
diff --git a/vendor/atomicgo.dev/schedule/doc.go b/vendor/atomicgo.dev/schedule/doc.go
new file mode 100644
index 00000000..4801fdb5
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/doc.go
@@ -0,0 +1,6 @@
+/*
+Package schedule provides a simple scheduler for Go.
+
+It can run a function at a given time, in a given duration, or repeatedly at a given interval.
+*/
+package schedule
diff --git a/vendor/atomicgo.dev/schedule/schedule.go b/vendor/atomicgo.dev/schedule/schedule.go
new file mode 100644
index 00000000..635d29d3
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/schedule.go
@@ -0,0 +1,116 @@
+package schedule
+
+import "time"
+
+// Task holds information about the running task and can be used to stop running tasks.
+type Task struct {
+ stop chan struct{}
+ nextExecution time.Time
+ startedAt time.Time
+}
+
+// newTask creates a new Task.
+func newTask() *Task {
+ return &Task{
+ stop: make(chan struct{}),
+ startedAt: time.Now(),
+ }
+}
+
+// StartedAt returns the time when the scheduler was started.
+func (s *Task) StartedAt() time.Time {
+ return s.startedAt
+}
+
+// NextExecutionTime returns the time when the next execution will happen.
+func (s *Task) NextExecutionTime() time.Time {
+ return s.nextExecution
+}
+
+// ExecutesIn returns the duration until the next execution.
+func (s *Task) ExecutesIn() time.Duration {
+ return time.Until(s.nextExecution)
+}
+
+// IsActive returns true if the scheduler is active.
+func (s *Task) IsActive() bool {
+ select {
+ case <-s.stop:
+ return false
+ default:
+ return true
+ }
+}
+
+// Wait blocks until the scheduler is stopped.
+// After and At will stop automatically after the task is executed.
+func (s *Task) Wait() {
+ <-s.stop
+}
+
+// Stop stops the scheduler.
+func (s *Task) Stop() {
+ close(s.stop)
+}
+
+// After executes the task after the given duration.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func After(d time.Duration, task func()) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = time.Now().Add(d)
+
+ go func() {
+ select {
+ case <-time.After(d):
+ task()
+ scheduler.Stop()
+ case <-scheduler.stop:
+ return
+ }
+ }()
+
+ return scheduler
+}
+
+// At executes the task at the given time.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func At(t time.Time, task func()) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = t
+
+ go func() {
+ select {
+ case <-time.After(time.Until(t)):
+ task()
+ scheduler.Stop()
+ case <-scheduler.stop:
+ return
+ }
+ }()
+
+ return scheduler
+}
+
+// Every executes the task in the given interval, as long as the task function returns true.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func Every(interval time.Duration, task func() bool) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = time.Now().Add(interval)
+
+ ticker := time.NewTicker(interval)
+
+ go func() {
+ for {
+ select {
+ case <-ticker.C:
+ task()
+ scheduler.nextExecution = time.Now().Add(interval)
+ case <-scheduler.stop:
+ ticker.Stop()
+ return
+ }
+ }
+ }()
+
+ return scheduler
+}
diff --git a/vendor/bitbucket.org/creachadair/shell/LICENSE b/vendor/bitbucket.org/creachadair/shell/LICENSE
deleted file mode 100644
index 10d72735..00000000
--- a/vendor/bitbucket.org/creachadair/shell/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2015, Michael J. Fromberger
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/bitbucket.org/creachadair/shell/README.md b/vendor/bitbucket.org/creachadair/shell/README.md
deleted file mode 100644
index 73282bed..00000000
--- a/vendor/bitbucket.org/creachadair/shell/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# shell
-
-http://godoc.org/bitbucket.org/creachadair/shell
-
-The `shell` package implements basic shell command-line splitting.
-
-
diff --git a/vendor/bitbucket.org/creachadair/shell/bitbucket-pipelines.yml b/vendor/bitbucket.org/creachadair/shell/bitbucket-pipelines.yml
deleted file mode 100644
index 8acd906c..00000000
--- a/vendor/bitbucket.org/creachadair/shell/bitbucket-pipelines.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-definitions:
- steps:
- - step: &Verify
- script:
- - PACKAGE_PATH="${GOPATH}/src/bitbucket.org/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}"
- - mkdir -pv "${PACKAGE_PATH}"
- - tar -cO --exclude-vcs --exclude=bitbucket-pipelines.yml . | tar -xv -C "${PACKAGE_PATH}"
- - cd "${PACKAGE_PATH}"
- - go version # log the version of Go we are using in this step
- - export GO111MODULE=on # enable modules inside $GOPATH
- - go get -v ./...
- - go build -v ./...
- - go test -v -race -cpu=1,4 ./...
- - go vet -v ./...
-
-pipelines:
- default: # run on each push
- - step:
- image: golang:1.16
- <<: *Verify
- - step:
- image: golang:1.17
- <<: *Verify
diff --git a/vendor/bitbucket.org/creachadair/shell/shell.go b/vendor/bitbucket.org/creachadair/shell/shell.go
deleted file mode 100644
index e4f8650f..00000000
--- a/vendor/bitbucket.org/creachadair/shell/shell.go
+++ /dev/null
@@ -1,325 +0,0 @@
-// Package shell supports splitting and joining of shell command strings.
-//
-// The Split function divides a string into whitespace-separated fields,
-// respecting single and double quotation marks as defined by the Shell Command
-// Language section of IEEE Std 1003.1 2013. The Quote function quotes
-// characters that would otherwise be subject to shell evaluation, and the Join
-// function concatenates quoted strings with spaces between them.
-//
-// The relationship between Split and Join is that given
-//
-// fields, ok := Split(Join(ss))
-//
-// the following relationship will hold:
-//
-// fields == ss && ok
-//
-package shell
-
-import (
- "bufio"
- "bytes"
- "io"
- "strings"
-)
-
-// These characters must be quoted to escape special meaning. This list
-// doesn't include the single quote.
-const mustQuote = "|&;<>()$`\\\"\t\n"
-
-// These characters should be quoted to escape special meaning, since in some
-// contexts they are special (e.g., "x=y" in command position, "*" for globs).
-const shouldQuote = `*?[#~=%`
-
-// These are the separator characters in unquoted text.
-const spaces = " \t\n"
-
-const allQuote = mustQuote + shouldQuote + spaces
-
-type state int
-
-const (
- stNone state = iota
- stBreak
- stBreakQ
- stWord
- stWordQ
- stSingle
- stDouble
- stDoubleQ
-)
-
-type class int
-
-const (
- clOther class = iota
- clBreak
- clNewline
- clQuote
- clSingle
- clDouble
-)
-
-type action int
-
-const (
- drop action = iota
- push
- xpush
- emit
-)
-
-// N.B. Benchmarking shows that array lookup is substantially faster than map
-// lookup here, but it requires caution when changing the state machine. In
-// particular:
-//
-// 1. The state and action values must be small integers.
-// 2. The update table must completely cover the state values.
-// 3. Each action slice must completely cover the action values.
-//
-var update = [...][]struct {
- state
- action
-}{
- stNone: {},
- stBreak: {
- clBreak: {stBreak, drop},
- clNewline: {stBreak, drop},
- clQuote: {stBreakQ, drop},
- clSingle: {stSingle, drop},
- clDouble: {stDouble, drop},
- clOther: {stWord, push},
- },
- stBreakQ: {
- clBreak: {stWord, push},
- clNewline: {stBreak, drop},
- clQuote: {stWord, push},
- clSingle: {stWord, push},
- clDouble: {stWord, push},
- clOther: {stWord, push},
- },
- stWord: {
- clBreak: {stBreak, emit},
- clNewline: {stBreak, emit},
- clQuote: {stWordQ, drop},
- clSingle: {stSingle, drop},
- clDouble: {stDouble, drop},
- clOther: {stWord, push},
- },
- stWordQ: {
- clBreak: {stWord, push},
- clNewline: {stWord, drop},
- clQuote: {stWord, push},
- clSingle: {stWord, push},
- clDouble: {stWord, push},
- clOther: {stWord, push},
- },
- stSingle: {
- clBreak: {stSingle, push},
- clNewline: {stSingle, push},
- clQuote: {stSingle, push},
- clSingle: {stWord, drop},
- clDouble: {stSingle, push},
- clOther: {stSingle, push},
- },
- stDouble: {
- clBreak: {stDouble, push},
- clNewline: {stDouble, push},
- clQuote: {stDoubleQ, drop},
- clSingle: {stDouble, push},
- clDouble: {stWord, drop},
- clOther: {stDouble, push},
- },
- stDoubleQ: {
- clBreak: {stDouble, xpush},
- clNewline: {stDouble, drop},
- clQuote: {stDouble, push},
- clSingle: {stDouble, xpush},
- clDouble: {stDouble, push},
- clOther: {stDouble, xpush},
- },
-}
-
-var classOf = [256]class{
- ' ': clBreak,
- '\t': clBreak,
- '\n': clNewline,
- '\\': clQuote,
- '\'': clSingle,
- '"': clDouble,
-}
-
-// A Scanner partitions input from a reader into tokens divided on space, tab,
-// and newline characters. Single and double quotation marks are handled as
-// described in http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02.
-type Scanner struct {
- buf *bufio.Reader
- cur bytes.Buffer
- st state
- err error
-}
-
-// NewScanner returns a Scanner that reads input from r.
-func NewScanner(r io.Reader) *Scanner {
- return &Scanner{
- buf: bufio.NewReader(r),
- st: stBreak,
- }
-}
-
-// Next advances the scanner and reports whether there are any further tokens
-// to be consumed.
-func (s *Scanner) Next() bool {
- if s.err != nil {
- return false
- }
- s.cur.Reset()
- for {
- c, err := s.buf.ReadByte()
- s.err = err
- if err == io.EOF {
- break
- } else if err != nil {
- return false
- }
- next := update[s.st][classOf[c]]
- s.st = next.state
- switch next.action {
- case push:
- s.cur.WriteByte(c)
- case xpush:
- s.cur.Write([]byte{'\\', c})
- case emit:
- return true // s.cur has a complete token
- case drop:
- continue
- default:
- panic("unknown action")
- }
- }
- return s.st != stBreak
-}
-
-// Text returns the text of the current token, or "" if there is none.
-func (s *Scanner) Text() string { return s.cur.String() }
-
-// Err returns the error, if any, that resulted from the most recent action.
-func (s *Scanner) Err() error { return s.err }
-
-// Complete reports whether the current token is complete, meaning that it is
-// unquoted or its quotes were balanced.
-func (s *Scanner) Complete() bool { return s.st == stBreak || s.st == stWord }
-
-// Rest returns an io.Reader for the remainder of the unconsumed input in s.
-// After calling this method, Next will always return false. The remainder
-// does not include the text of the current token at the time Rest is called.
-func (s *Scanner) Rest() io.Reader {
- s.st = stNone
- s.cur.Reset()
- s.err = io.EOF
- return s.buf
-}
-
-// Each calls f for each token in the scanner until the input is exhausted, f
-// returns false, or an error occurs.
-func (s *Scanner) Each(f func(tok string) bool) error {
- for s.Next() {
- if !f(s.Text()) {
- return nil
- }
- }
- if err := s.Err(); err != io.EOF {
- return err
- }
- return nil
-}
-
-// Split returns the remaining tokens in s, not including the current token if
-// there is one. Any tokens already consumed are still returned, even if there
-// is an error.
-func (s *Scanner) Split() []string {
- var tokens []string
- for s.Next() {
- tokens = append(tokens, s.Text())
- }
- return tokens
-}
-
-// Split partitions s into tokens divided on space, tab, and newline characters
-// using a *Scanner. Leading and trailing whitespace are ignored.
-//
-// The Boolean flag reports whether the final token is "valid", meaning there
-// were no unclosed quotations in the string.
-func Split(s string) ([]string, bool) {
- sc := NewScanner(strings.NewReader(s))
- ss := sc.Split()
- return ss, sc.Complete()
-}
-
-func quotable(s string) (hasQ, hasOther bool) {
- const (
- quote = 1
- other = 2
- all = quote + other
- )
- var v uint
- for i := 0; i < len(s) && v < all; i++ {
- if s[i] == '\'' {
- v |= quote
- } else if strings.IndexByte(allQuote, s[i]) >= 0 {
- v |= other
- }
- }
- return v"e != 0, v&other != 0
-}
-
-// Quote returns a copy of s in which shell metacharacters are quoted to
-// protect them from evaluation.
-func Quote(s string) string {
- var buf bytes.Buffer
- return quote(s, &buf)
-}
-
-// quote implements quotation, using the provided buffer as scratch space. The
-// existing contents of the buffer are clobbered.
-func quote(s string, buf *bytes.Buffer) string {
- if s == "" {
- return "''"
- }
- hasQ, hasOther := quotable(s)
- if !hasQ && !hasOther {
- return s // fast path: nothing needs quotation
- }
-
- buf.Reset()
- inq := false
- for i := 0; i < len(s); i++ {
- ch := s[i]
- if ch == '\'' {
- if inq {
- buf.WriteByte('\'')
- inq = false
- }
- buf.WriteByte('\\')
- } else if !inq && hasOther {
- buf.WriteByte('\'')
- inq = true
- }
- buf.WriteByte(ch)
- }
- if inq {
- buf.WriteByte('\'')
- }
- return buf.String()
-}
-
-// Join quotes each element of ss with Quote and concatenates the resulting
-// strings separated by spaces.
-func Join(ss []string) string {
- quoted := make([]string, len(ss))
- var buf bytes.Buffer
- for i, s := range ss {
- quoted[i] = quote(s, &buf)
- }
- return strings.Join(quoted, " ")
-}
diff --git a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/client.go b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/client.go
index a12c4956..4eb92129 100644
--- a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/client.go
+++ b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/client.go
@@ -3,6 +3,7 @@ package vault
import (
"encoding/json"
"log"
+ "net/http"
)
// clientsResource is the HTTP URL path component for the clients resource
@@ -24,13 +25,12 @@ type Client struct {
// Client gets the client with id from the DSV of the given tenant
func (v Vault) Client(id string) (*Client, error) {
- client := &Client{vault: v}
- data, err := v.accessResource("GET", clientsResource, id, nil)
-
+ data, err := v.accessResource(http.MethodGet, clientsResource, id, nil)
if err != nil {
return nil, err
}
+ client := &Client{vault: v}
if err := json.Unmarshal(data, client); err != nil {
log.Printf("[DEBUG] error parsing response from /%s/%s: %q", clientsResource, id, data)
return nil, err
@@ -40,17 +40,15 @@ func (v Vault) Client(id string) (*Client, error) {
// Delete deletes the client from the DSV of the given tenant
func (c Client) Delete() error {
- if _, err := c.vault.accessResource("DELETE", clientsResource, c.ClientID, nil); err != nil {
+ if _, err := c.vault.accessResource(http.MethodDelete, clientsResource, c.ClientID, nil); err != nil {
return err
}
-
return nil
}
// New creates a new Client given a roleName
func (v Vault) New(client *Client) error {
- data, err := v.accessResource("POST", clientsResource, "/", client)
-
+ data, err := v.accessResource(http.MethodPost, clientsResource, "/", client)
if err != nil {
return err
}
@@ -59,6 +57,5 @@ func (v Vault) New(client *Client) error {
log.Printf("[DEBUG] error parsing response from /%s: %q", clientsResource, data)
return err
}
-
return nil
}
diff --git a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/http.go b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/http.go
index e540d984..191ba533 100644
--- a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/http.go
+++ b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/http.go
@@ -13,7 +13,6 @@ func handleResponse(res *http.Response, err error) ([]byte, error) {
}
data, err := ioutil.ReadAll(res.Body)
-
if err != nil {
return nil, err
}
@@ -22,6 +21,5 @@ func handleResponse(res *http.Response, err error) ([]byte, error) {
if res.StatusCode > 199 && res.StatusCode < 300 {
return data, nil
}
-
return nil, fmt.Errorf("%s: %s", res.Status, string(data))
}
diff --git a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/role.go b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/role.go
index dd7550d7..34e6a21d 100644
--- a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/role.go
+++ b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/role.go
@@ -3,6 +3,7 @@ package vault
import (
"encoding/json"
"log"
+ "net/http"
)
// rolesResource is the HTTP URL path component for the roles resource
@@ -18,18 +19,16 @@ type roleResource struct {
type Role struct {
resourceMetadata
roleResource
- vault Vault
}
// Role gets the role named name from the DSV of the given tenant
func (v Vault) Role(name string) (*Role, error) {
- role := &Role{vault: v}
- data, err := v.accessResource("GET", rolesResource, name, nil)
-
+ data, err := v.accessResource(http.MethodGet, rolesResource, name, nil)
if err != nil {
return nil, err
}
+ role := &Role{}
if err := json.Unmarshal(data, role); err != nil {
log.Printf("[DEBUG] error parsing response from /%s/%s: %q", rolesResource, name, data)
return nil, err
diff --git a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/secret.go b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/secret.go
index 6f357e26..2b4836ea 100644
--- a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/secret.go
+++ b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/secret.go
@@ -3,6 +3,7 @@ package vault
import (
"encoding/json"
"log"
+ "net/http"
)
// secretsResource is the HTTP URL path component for the secrets resource
@@ -19,21 +20,53 @@ type secretResource struct {
type Secret struct {
resourceMetadata
secretResource
- vault Vault
}
-// Secret gets the secret at path from the DSV of the given tenant
+// Secret [gets the secret] at path from the DSV of the given tenant.
+//
+// [gets the secret]: https://dsv.secretsvaultcloud.com/api#operation/getSecret
func (v Vault) Secret(path string) (*Secret, error) {
- secret := &Secret{vault: v}
- data, err := v.accessResource("GET", secretsResource, path, nil)
-
+ data, err := v.accessResource(http.MethodGet, secretsResource, path, nil)
if err != nil {
return nil, err
}
+ secret := &Secret{}
if err := json.Unmarshal(data, secret); err != nil {
log.Printf("[DEBUG] error parsing response from /%s/%s: %q", secretsResource, path, data)
return nil, err
}
return secret, nil
}
+
+// DeleteSecret [deletes the secret] at path from the DSV of the given tenant.
+//
+// [deletes the secret]: https://dsv.secretsvaultcloud.com/api#operation/deleteSecret
+func (v Vault) DeleteSecret(path string) error {
+ _, err := v.accessResource(http.MethodDelete, secretsResource, path, nil)
+ return err
+}
+
+// SecretCreateRequest represents the request body of the CreateSecret operation.
+type SecretCreateRequest struct {
+ Attributes map[string]interface{} `json:"attributes"`
+ Data map[string]interface{} `json:"data"`
+ Description string `json:"description"`
+}
+
+// CreateSecret [creates the secret] at path in the DSV of the given tenant.
+//
+// [creates the secret]: https://dsv.secretsvaultcloud.com/api#operation/createSecret
+func (v Vault) CreateSecret(path string, req *SecretCreateRequest) (*Secret, error) {
+ d, err := v.accessResource(http.MethodPost, secretsResource, path, req)
+ if err != nil {
+ return nil, err
+ }
+
+ secret := &Secret{}
+ if err := json.Unmarshal(d, secret); err != nil {
+ log.Printf("[DEBUG] error parsing response from /%s/%s: %q", secretsResource, path, d)
+ return nil, err
+ }
+ return secret, nil
+}
diff --git a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/vault.go b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/vault.go
index 5348a4ca..622b37fc 100644
--- a/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/vault.go
+++ b/vendor/github.com/DelineaXPM/dsv-sdk-go/v2/vault/vault.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"log"
"net/http"
"strings"
@@ -84,43 +85,37 @@ func New(config Configuration) (*Vault, error) {
// accessResource uses the accessToken to access the API resource.
// It assumes an appropriate combination of method, resource, path and input.
func (v Vault) accessResource(method, resource, path string, input interface{}) ([]byte, error) {
- accessToken, err := v.getAccessToken()
-
- if err != nil {
- log.Print("[DEBUG] error getting accessToken:", err)
- return nil, err
- }
-
switch resource {
case clientsResource, rolesResource, secretsResource:
default:
- message := "unrecognized resource"
-
- log.Printf("[DEBUG] %s: %s", message, resource)
- return nil, fmt.Errorf(message)
+ return nil, fmt.Errorf("unrecognized resource: %s", resource)
}
- body := bytes.NewBuffer([]byte{})
+ accessToken, err := v.getAccessToken()
+ if err != nil {
+ log.Print("[DEBUG] error getting accessToken: ", err)
+ return nil, err
+ }
+ var body io.Reader
if input != nil {
- if data, err := json.Marshal(input); err == nil {
- body = bytes.NewBuffer(data)
- } else {
+ data, err := json.Marshal(input)
+ if err != nil {
log.Print("[DEBUG] marshaling the request body to JSON:", err)
return nil, err
}
+ body = bytes.NewReader(data)
}
req, err := http.NewRequest(method, v.urlFor(resource, path), body)
- req.Header.Add("Authorization", "Bearer "+accessToken)
-
if err != nil {
log.Printf("[DEBUG] creating req: %s /%s/%s: %s", method, resource, path, err)
return nil, err
}
+ req.Header.Add("Authorization", "Bearer "+accessToken)
switch method {
- case "POST", "PUT":
+ case http.MethodPost, http.MethodPut:
req.Header.Set("Content-Type", "application/json")
}
@@ -132,18 +127,22 @@ func (v Vault) accessResource(method, resource, path string, input interface{})
}
type accessTokenRequest struct {
- GrantType string `json:"grant_type"`
- Provider string `json:"provider"`
- Password string `json:"password"`
- ClientID string `json:"client_id"`
- ClientSecret string `json:"client_secret"`
- RefreshToken string `json:"refresh_token"`
- AwsBody string `json:"aws_body"`
- AwsHeaders string `json:"aws_headers"`
+ GrantType string `json:"grant_type"`
+
+ // Fields for "client_credentials" grant type.
+ ClientID string `json:"client_id,omitempty"`
+ ClientSecret string `json:"client_secret,omitempty"`
+
+ // Fields for "aws_iam" grant type.
+ AwsBody string `json:"aws_body,omitempty"`
+ AwsHeaders string `json:"aws_headers,omitempty"`
+}
+
+type accessTokenResponse struct {
+ AccessToken string `json:"accessToken"`
}
-// getAccessToken uses the client_id and client_secret, to call the token
-// endpoint and get an accessGrant.
+// getAccessToken returns access token fetched from DSV.
func (v Vault) getAccessToken() (string, error) {
var rBody accessTokenRequest
switch v.Provider {
@@ -168,32 +167,24 @@ func (v Vault) getAccessToken() (string, error) {
}
request, err := json.Marshal(&rBody)
-
if err != nil {
- log.Print("[WARN] marshalling grantRequest")
- return "", err
+ return "", fmt.Errorf("marshalling token request body: %w", err)
}
url := v.urlFor("token", "")
response, err := handleResponse(http.Post(url, "application/json", bytes.NewReader(request)))
if err != nil {
- log.Print("[DEBUG] grant response error:", err)
- return "", err
+ return "", fmt.Errorf("fetching token: %w", err)
}
- grant := struct {
- AccessToken, TokenType string
- ExpiresIn int
- // TODO cache the grant until it expires
- }{}
-
- if err = json.Unmarshal(response, &grant); err != nil {
- log.Print("[INFO] parsing grant response:", err)
- return "", err
+ // TODO: cache the token until it expires.
+ resp := &accessTokenResponse{}
+ if err = json.Unmarshal(response, &resp); err != nil {
+ return "", fmt.Errorf("unmarshalling token response: %w", err)
}
- return grant.AccessToken, nil
+ return resp.AccessToken, nil
}
// urlFor the URL of the given resource and path in the current Vault
diff --git a/vendor/github.com/bitfield/script/CODE_OF_CONDUCT.md b/vendor/github.com/bitfield/script/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..5b29514a
--- /dev/null
+++ b/vendor/github.com/bitfield/script/CODE_OF_CONDUCT.md
@@ -0,0 +1,40 @@
+# CONTRIBUTOR CODE OF CONDUCT
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others’ private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at go@bitfieldconsulting.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
diff --git a/vendor/github.com/bitfield/script/CONTRIBUTING.md b/vendor/github.com/bitfield/script/CONTRIBUTING.md
index 4dd555dd..930a603b 100644
--- a/vendor/github.com/bitfield/script/CONTRIBUTING.md
+++ b/vendor/github.com/bitfield/script/CONTRIBUTING.md
@@ -38,7 +38,7 @@ Test data should go in the `testdata` directory. If you create a file of data fo
### Use the standard library
- All `script` tests use the standard Go `testing` library; they don't use `testify` or `gock` or any of the other tempting and shiny test libraries. There's nothing wrong with those libraries, but it's good to keep things consistent, and not import any libraries we don't absolutely need.
+All `script` tests use the standard Go `testing` library; they don't use `testify` or `gock` or any of the other tempting and shiny test libraries. There's nothing wrong with those libraries, but it's good to keep things consistent, and not import any libraries we don't absolutely need.
You'll get the feel of things by reading the existing tests, and maybe copying and adapting them for your own feature.
@@ -123,13 +123,13 @@ Any change to the `script` API should also be accompanied by an update to the RE
Here's a handy checklist for making sure your PR will be accepted as quickly as possible.
- - [ ] Have you opened an issue to discuss the feature and agree its general design?
- - [ ] Do you have a use case and, ideally, an example program using the feature?
- - [ ] Do you have tests covering 90%+ of the feature code (and, of course passing)
- - [ ] Have you added your method to the `doMethodsOnPipe` stress tests?
- - [ ] Have you written complete and accurate doc comments?
- - [ ] Have you updated the README and its table of contents?
- - [ ] You rock. Thanks a lot.
+- [ ] Have you opened an issue to discuss the feature and agree its general design?
+- [ ] Do you have a use case and, ideally, an example program using the feature?
+- [ ] Do you have tests covering 90%+ of the feature code (and, of course passing)
+- [ ] Have you added your method to the `doMethodsOnPipe` stress tests?
+- [ ] Have you written complete and accurate doc comments?
+- [ ] Have you updated the README and its table of contents?
+- [ ] You rock. Thanks a lot.
# After submitting your PR
@@ -165,4 +165,8 @@ In fact, doing a _proper_ and serious code review is a time-consuming business.
Open source maintainers are just regular folk with jobs, kids, and zero free time or energy. They may not be able to drop everything and put in several hours on your PR. The task may have to wait a week or two until they can get sufficient time and peace and quiet to work on it. Don't pester them. It's fine to add a comment on the PR if you haven't heard anything for a while, asking if the reviewer's been able to look at it and whether there's anything you can do to help speed things up. Comments like 'Y U NO MERGE' are unlikely to elicit a positive response.
-Thanks again for helping out!
\ No newline at end of file
+Thanks again for helping out!
+
+## Code of Conduct
+
+As a contributor you can help keep the `script` community inclusive and open to everyone. Please read and adhere to our [Code of Conduct](CODE_OF_CONDUCT.md).
diff --git a/vendor/github.com/bitfield/script/README.md b/vendor/github.com/bitfield/script/README.md
index 5322d383..b57324e7 100644
--- a/vendor/github.com/bitfield/script/README.md
+++ b/vendor/github.com/bitfield/script/README.md
@@ -1,4 +1,7 @@
-[![Go Reference](https://pkg.go.dev/badge/github.com/bitfield/script.svg)](https://pkg.go.dev/github.com/bitfield/script)[![Go Report Card](https://goreportcard.com/badge/github.com/bitfield/script)](https://goreportcard.com/report/github.com/bitfield/script)[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go)[![CircleCI](https://circleci.com/gh/bitfield/script.svg?style=svg)](https://circleci.com/gh/bitfield/script)
+[![Go Reference](https://pkg.go.dev/badge/github.com/bitfield/script.svg)](https://pkg.go.dev/github.com/bitfield/script)
+[![Go Report Card](https://goreportcard.com/badge/github.com/bitfield/script)](https://goreportcard.com/report/github.com/bitfield/script)
+[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go)
+![Tests](https://github.com/bitfield/script/actions/workflows/test.yml/badge.svg)
```go
import "github.com/bitfield/script"
@@ -25,28 +28,30 @@ If you're already familiar with shell scripting and the Unix toolset, here is a
| Unix / shell | `script` equivalent |
| ------------------ | ------------------- |
-| (any program name) | [`Exec()`](https://pkg.go.dev/github.com/bitfield/script#Exec) |
-| `[ -f FILE ]` | [`IfExists()`](https://pkg.go.dev/github.com/bitfield/script#IfExists) |
-| `>` | [`WriteFile()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WriteFile) |
-| `>>` | [`AppendFile()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.AppendFile) |
-| `$*` | [`Args()`](https://pkg.go.dev/github.com/bitfield/script#Args) |
-| `basename` | [`Basename()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Basename) |
-| `cat` | [`File()`](https://pkg.go.dev/github.com/bitfield/script#File) / [`Concat()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Concat) |
-| `cut` | [`Column()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Column) |
-| `dirname` | [`Dirname()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Dirname) |
-| `echo` | [`Echo()`](https://pkg.go.dev/github.com/bitfield/script#Echo) |
-| `grep` | [`Match()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Match) / [`MatchRegexp()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.MatchRegexp) |
-| `grep -v` | [`Reject()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Reject) / [`RejectRegexp()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.RejectRegexp) |
-| `head` | [`First()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.First) |
-| `find -type f` | [`FindFiles`](https://pkg.go.dev/github.com/bitfield/script#FindFiles) |
+| (any program name) | [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Exec) |
+| `[ -f FILE ]` | [`IfExists`](https://pkg.go.dev/github.com/bitfield/script#IfExists) |
+| `>` | [`WriteFile`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WriteFile) |
+| `>>` | [`AppendFile`](https://pkg.go.dev/github.com/bitfield/script#Pipe.AppendFile) |
+| `$*` | [`Args`](https://pkg.go.dev/github.com/bitfield/script#Args) |
+| `basename` | [`Basename`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Basename) |
+| `cat` | [`File`](https://pkg.go.dev/github.com/bitfield/script#File) / [`Concat`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Concat) |
+| `curl` | [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do) / [`Get`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Get) / [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) |
+| `cut` | [`Column`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Column) |
+| `dirname` | [`Dirname`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Dirname) |
+| `echo` | [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Echo) |
+| `find` | [`FindFiles`](https://pkg.go.dev/github.com/bitfield/script#FindFiles) |
+| `grep` | [`Match`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Match) / [`MatchRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.MatchRegexp) |
+| `grep -v` | [`Reject`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Reject) / [`RejectRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.RejectRegexp) |
+| `head` | [`First`](https://pkg.go.dev/github.com/bitfield/script#Pipe.First) |
| `jq` | [`JQ`](https://pkg.go.dev/github.com/bitfield/script#Pipe.JQ) |
-| `ls` | [`ListFiles()`](https://pkg.go.dev/github.com/bitfield/script#ListFiles) |
-| `sed` | [`Replace()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Replace) / [`ReplaceRegexp()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ReplaceRegexp) |
-| `sha256sum` | [`SHA256Sum()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.SHA256Sum) / [`SHA256Sums()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.SHA256Sums) |
-| `tail` | [`Last()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Last) |
-| `uniq -c` | [`Freq()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Freq) |
-| `wc -l` | [`CountLines()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.CountLines) |
-| `xargs` | [`ExecForEach()`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ExecForEach) |
+| `ls` | [`ListFiles`](https://pkg.go.dev/github.com/bitfield/script#ListFiles) |
+| `sed` | [`Replace`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Replace) / [`ReplaceRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ReplaceRegexp) |
+| `sha256sum` | [`SHA256Sum`](https://pkg.go.dev/github.com/bitfield/script#Pipe.SHA256Sum) / [`SHA256Sums`](https://pkg.go.dev/github.com/bitfield/script#Pipe.SHA256Sums) |
+| `tail` | [`Last`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Last) |
+| `tee` | [`Tee`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Tee) |
+| `uniq -c` | [`Freq`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Freq) |
+| `wc -l` | [`CountLines`](https://pkg.go.dev/github.com/bitfield/script#Pipe.CountLines) |
+| `xargs` | [`ExecForEach`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ExecForEach) |
# Some examples
@@ -62,7 +67,7 @@ That looks straightforward enough, but suppose you now want to count the lines i
numLines, err := script.File("test.txt").CountLines()
```
-For something a bit more challenging, let's try counting the number of lines in the file that match the string "Error":
+For something a bit more challenging, let's try counting the number of lines in the file that match the string `Error`:
```go
numErrors, err := script.File("test.txt").Match("Error").CountLines()
@@ -92,31 +97,97 @@ Maybe we're only interested in the first 10 matches. No problem:
script.Args().Concat().Match("Error").First(10).Stdout()
```
-What's that? You want to append that output to a file instead of printing it to the terminal? _You've got some attitude, mister_.
+What's that? You want to append that output to a file instead of printing it to the terminal? *You've got some attitude, mister*. But okay:
```go
script.Args().Concat().Match("Error").First(10).AppendFile("/var/log/errors.txt")
```
-If the data is JSON, we can do better than simple string-matching. We can use [JQ](https://stedolan.github.io/jq/) queries:
+And if we'd like to send the output to the terminal *as well as* to the file, we can do that:
```go
-script.File("commits.json").JQ(".[0] | {message: .commit.message, name: .commit.committer.name}").Stdout()
+script.Echo("data").Tee().AppendFile("data.txt")
```
-Suppose we want to execute some external program instead of doing the work ourselves. We can do that too:
+We're not limited to getting data only from files or standard input. We can get it from HTTP requests too:
+
+```go
+script.Get("https://wttr.in/London?format=3").Stdout()
+// Output:
+// London: 🌦 +13°C
+```
+
+That's great for simple GET requests, but suppose we want to *send* some data in the body of a POST request, for example. Here's how that works:
+
+```go
+script.Echo(data).Post(URL).Stdout()
+```
+
+If we need to customise the HTTP behaviour in some way, such as using our own HTTP client, we can do that:
+
+```go
+script.NewPipe().WithHTTPClient(&http.Client{
+ Timeout: 10 * time.Second,
+}).Get("https://example.com").Stdout()
+```
+
+Or maybe we need to set some custom header on the request. No problem. We can just create the request in the usual way, and set it up however we want. Then we pass it to `Do`, which will actually perform the request:
+
+```go
+req, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
+req.Header.Add("Authorization", "Bearer "+token)
+script.Do(req).Stdout()
+```
+
+The HTTP server could return some non-okay response, though; for example, “404 Not Found”. So what happens then?
+
+In general, when any pipe stage (such as `Do`) encounters an error, it produces no output to subsequent stages. And `script` treats HTTP response status codes outside the range 200-299 as errors. So the answer for the previous example is that we just won't *see* any output from this program if the server returns an error response.
+
+Instead, the pipe “remembers” any error that occurs, and we can retrieve it later by calling its `Error` method, or by using a *sink* method such as `String`, which returns an `error` value along with the result.
+
+`Stdout` also returns an error, plus the number of bytes successfully written (which we don't care about for this particular case). So we can check that error, which is always a good idea in Go:
+
+```go
+_, err := script.Do(req).Stdout()
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+If, as is common, the data we get from an HTTP request is in JSON format, we can use [JQ](https://stedolan.github.io/jq/) queries to interrogate it:
+
+```go
+data, err := script.Do(req).JQ(".[0] | {message: .commit.message, name: .commit.committer.name}").String()
+```
+
+We can also run external programs and get their output:
```go
script.Exec("ping 127.0.0.1").Stdout()
```
-But maybe we don't know the arguments yet; we might get them from the user, for example. We'd like to be able to run the external command repeatedly, each time passing it the next line of input. No worries:
+Note that `Exec` runs the command concurrently: it doesn't wait for the command to complete before returning any output. That's good, because this `ping` command will run forever (or until we get bored).
+
+Instead, when we read from the pipe using `Stdout`, we see each line of output as it's produced:
+
+```
+PING 127.0.0.1 (127.0.0.1): 56 data bytes
+64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.056 ms
+64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.054 ms
+...
+```
+
+In the `ping` example, we knew the exact arguments we wanted to send the command, and we just needed to run it once. But what if we don't know the arguments yet? We might get them from the user, for example.
+
+We might like to be able to run the external command repeatedly, each time passing it the next line of data from the pipe as an argument. No worries:
```go
script.Args().ExecForEach("ping -c 1 {{.}}").Stdout()
```
-If there isn't a built-in operation that does what we want, we can just write our own:
+That `{{.}}` is standard Go template syntax; it'll substitute each line of data from the pipe into the command line before it's executed. You can write as fancy a Go template expression as you want here (but this simple example probably covers most use cases).
+
+If there isn't a built-in operation that does what we want, we can just write our own, using `Filter`:
```go
script.Echo("hello world").Filter(func (r io.Reader, w io.Writer) error {
@@ -129,7 +200,11 @@ script.Echo("hello world").Filter(func (r io.Reader, w io.Writer) error {
// filtered 11 bytes
```
-Notice that the "hello world" appeared before the "filtered n bytes". Filters run concurrently, so the pipeline can start producing output before the input has been fully read.
+The `func` we supply to `Filter` takes just two parameters: a reader to read from, and a writer to write to. The reader reads the previous stages of the pipe, as you might expect, and anything written to the writer goes to the *next* stage of the pipe.
+
+If our `func` returns some error, then, just as with the `Do` example, the pipe's error status is set, and subsequent stages become a no-op.
+
+Filters run concurrently, so the pipeline can start producing output before the input has been fully read, as it did in the `ping` example. In fact, most built-in pipe methods, including `Exec`, are implemented *using* `Filter`.
If we want to scan input line by line, we could do that with a `Filter` function that creates a `bufio.Scanner` on its input, but we don't need to:
@@ -193,12 +268,15 @@ These are functions that create a pipe with a given contents:
| Source | Contents |
| -------- | ------------- |
| [`Args`](https://pkg.go.dev/github.com/bitfield/script#Args) | command-line arguments
+| [`Do`](https://pkg.go.dev/github.com/bitfield/script#Do) | HTTP response
| [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Echo) | a string
| [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Exec) | command output
| [`File`](https://pkg.go.dev/github.com/bitfield/script#File) | file contents
| [`FindFiles`](https://pkg.go.dev/github.com/bitfield/script#FindFiles) | recursive file listing
+| [`Get`](https://pkg.go.dev/github.com/bitfield/script#Get) | HTTP response
| [`IfExists`](https://pkg.go.dev/github.com/bitfield/script#IfExists) | do something only if some file exists
| [`ListFiles`](https://pkg.go.dev/github.com/bitfield/script#ListFiles) | file listing (including wildcards)
+| [`Post`](https://pkg.go.dev/github.com/bitfield/script#Post) | HTTP response
| [`Slice`](https://pkg.go.dev/github.com/bitfield/script#Slice) | slice elements, one per line
| [`Stdin`](https://pkg.go.dev/github.com/bitfield/script#Stdin) | standard input
@@ -212,6 +290,7 @@ Filters are methods on an existing pipe that also return a pipe, allowing you to
| [`Column`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Column) | Nth column of input |
| [`Concat`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Concat) | contents of multiple files |
| [`Dirname`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Dirname) | removes filename from each line, leaving only leading path components |
+| [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do) | response to supplied HTTP request |
| [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Echo) | all input replaced by given string |
| [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Exec) | filtered through external command |
| [`ExecForEach`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ExecForEach) | execute given command template for each line of input |
@@ -220,18 +299,21 @@ Filters are methods on an existing pipe that also return a pipe, allowing you to
| [`FilterScan`](https://pkg.go.dev/github.com/bitfield/script#Pipe.FilterScan) | user-supplied function filtering each line to a writer |
| [`First`](https://pkg.go.dev/github.com/bitfield/script#Pipe.First) | first N lines of input |
| [`Freq`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Freq) | frequency count of unique input lines, most frequent first |
+| [`Get`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Get) | response to HTTP GET on supplied URL |
| [`Join`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Join) | replace all newlines with spaces |
| [`JQ`](https://pkg.go.dev/github.com/bitfield/script#Pipe.JQ) | result of `jq` query |
| [`Last`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Last) | last N lines of input|
| [`Match`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Match) | lines matching given string |
| [`MatchRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.MatchRegexp) | lines matching given regexp |
+| [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) | response to HTTP POST on supplied URL |
| [`Reject`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Reject) | lines not matching given string |
| [`RejectRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.RejectRegexp) | lines not matching given regexp |
| [`Replace`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Replace) | matching text replaced with given string |
| [`ReplaceRegexp`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ReplaceRegexp) | matching text replaced with given string |
| [`SHA256Sums`](https://pkg.go.dev/github.com/bitfield/script#Pipe.SHA256Sums) | SHA-256 hashes of each listed file |
+| [`Tee`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Tee) | input copied to supplied writers |
-Note that filters run concurrently, rather than producing nothing until each stage has fully read its input. This is convenient for executing long-running comands, for example. If you do need to wait for the pipeline to complete, call `Wait`.
+Note that filters run concurrently, rather than producing nothing until each stage has fully read its input. This is convenient for executing long-running comands, for example. If you do need to wait for the pipeline to complete, call [`Wait`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Wait).
## Sinks
@@ -254,6 +336,8 @@ Sinks are methods that return some data from a pipe, ending the pipeline and ext
| Version | New |
| ----------- | ------- |
+| v0.22.0 | [`Tee`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Tee), [`WithStderr`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithStderr) |
+| v0.21.0 | HTTP support: [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do), [`Get`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Get), [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) |
| v0.20.0 | [`JQ`](https://pkg.go.dev/github.com/bitfield/script#Pipe.JQ) |
# Contributing
diff --git a/vendor/github.com/bitfield/script/script.go b/vendor/github.com/bitfield/script/script.go
index d3a643db..da7e2fe5 100644
--- a/vendor/github.com/bitfield/script/script.go
+++ b/vendor/github.com/bitfield/script/script.go
@@ -8,6 +8,8 @@ import (
"encoding/json"
"fmt"
"io"
+ "math"
+ "net/http"
"os"
"os/exec"
"path/filepath"
@@ -18,246 +20,117 @@ import (
"sync"
"text/template"
- "bitbucket.org/creachadair/shell"
"github.com/itchyny/gojq"
+ "mvdan.cc/sh/v3/shell"
)
-// ReadAutoCloser represents a pipe source that will be automatically closed
-// once it has been fully read.
-type ReadAutoCloser struct {
- r io.ReadCloser
-}
-
-// Read reads up to len(buf) bytes from the data source into buf. It returns the
-// number of bytes read and any error encountered. At end of file, Read returns
-// 0, io.EOF. In the EOF case, the data source will be closed.
-func (a ReadAutoCloser) Read(buf []byte) (n int, err error) {
- if a.r == nil {
- return 0, io.EOF
- }
- n, err = a.r.Read(buf)
- if err == io.EOF {
- a.Close()
- }
- return n, err
-}
-
-// Close closes the data source associated with a, and returns the result of
-// that close operation.
-func (a ReadAutoCloser) Close() error {
- if a.r == nil {
- return nil
- }
- return a.r.(io.Closer).Close()
-}
-
-// NewReadAutoCloser returns an ReadAutoCloser wrapping the supplied Reader. If
-// the Reader is not a Closer, it will be wrapped in a NopCloser to make it
-// closable.
-func NewReadAutoCloser(r io.Reader) ReadAutoCloser {
- if _, ok := r.(io.Closer); !ok {
- return ReadAutoCloser{io.NopCloser(r)}
- }
- rc, ok := r.(io.ReadCloser)
- if !ok {
- // This can never happen, but just in case it does...
- panic("internal error: type assertion to io.ReadCloser failed")
- }
- return ReadAutoCloser{rc}
-}
-
-// Pipe represents a pipe object with an associated ReadAutoCloser.
+// Pipe represents a pipe object with an associated [ReadAutoCloser].
type Pipe struct {
- Reader ReadAutoCloser
- stdout io.Writer
+ // Reader is the underlying reader.
+ Reader ReadAutoCloser
+ stdout, stderr io.Writer
+ httpClient *http.Client
// because pipe stages are concurrent, protect 'err'
mu *sync.Mutex
err error
}
-// NewPipe returns a pointer to a new empty pipe.
-func NewPipe() *Pipe {
- return &Pipe{
- Reader: ReadAutoCloser{},
- mu: &sync.Mutex{},
- err: nil,
- stdout: os.Stdout,
- }
-}
-
-// Close closes the pipe's associated reader. This is a no-op if the reader is
-// not also a Closer.
-func (p *Pipe) Close() error {
- return p.Reader.Close()
-}
-
-// Error returns any error present on the pipe, or nil otherwise.
-func (p *Pipe) Error() error {
- if p.mu == nil { // uninitialised pipe
- return nil
- }
- p.mu.Lock()
- defer p.mu.Unlock()
- return p.err
-}
-
-var exitStatusPattern = regexp.MustCompile(`exit status (\d+)$`)
-
-// ExitStatus returns the integer exit status of a previous command, if the
-// pipe's error status is set, and if the error matches the pattern "exit status
-// %d". Otherwise, it returns zero.
-func (p *Pipe) ExitStatus() int {
- if p.Error() == nil {
- return 0
- }
- match := exitStatusPattern.FindStringSubmatch(p.Error().Error())
- if len(match) < 2 {
- return 0
- }
- status, err := strconv.Atoi(match[1])
- if err != nil {
- // This seems unlikely, but...
- return 0
- }
- return status
-}
-
-// Read reads up to len(b) bytes from the data source into b. It returns the
-// number of bytes read and any error encountered. At end of file, or on a nil
-// pipe, Read returns 0, io.EOF.
-//
-// Unlike most sinks, Read does not necessarily read the whole contents of the
-// pipe. It will read as many bytes as it takes to fill the slice.
-func (p *Pipe) Read(b []byte) (int, error) {
- return p.Reader.Read(b)
-}
-
-// SetError sets the specified error on the pipe.
-func (p *Pipe) SetError(err error) {
- if p.mu == nil { // uninitialised pipe
- return
- }
- p.mu.Lock()
- defer p.mu.Unlock()
- p.err = err
-}
-
-// WithReader sets the pipe's input to the specified reader. If necessary, the
-// reader will be automatically closed once it has been completely read.
-func (p *Pipe) WithReader(r io.Reader) *Pipe {
- p.Reader = NewReadAutoCloser(r)
- return p
-}
-
-// WithStdout sets the pipe's standard output to the specified reader, instead
-// of the default os.Stdout.
-func (p *Pipe) WithStdout(w io.Writer) *Pipe {
- p.stdout = w
- return p
-}
-
-// WithError sets the specified error on the pipe and returns the modified pipe.
-func (p *Pipe) WithError(err error) *Pipe {
- p.SetError(err)
- return p
+// Args creates a pipe containing the program's command-line arguments from
+// [os.Args], excluding the program name, one per line.
+func Args() *Pipe {
+ return Slice(os.Args[1:])
}
-// Args creates a pipe containing the program's command-line arguments, one per
-// line.
-func Args() *Pipe {
- var s strings.Builder
- for _, a := range os.Args[1:] {
- s.WriteString(a + "\n")
- }
- return Echo(s.String())
+// Do creates a pipe that makes the HTTP request req and produces the response.
+// See [Pipe.Do] for how the HTTP response status is interpreted.
+func Do(req *http.Request) *Pipe {
+ return NewPipe().Do(req)
}
-// Echo creates a pipe containing the supplied string.
+// Echo creates a pipe containing the string s.
func Echo(s string) *Pipe {
return NewPipe().WithReader(strings.NewReader(s))
}
-// Exec runs an external command and creates a pipe containing its combined
-// output (stdout and stderr).
-//
-// If the command had a non-zero exit status, the pipe's error status will also
-// be set to the string "exit status X", where X is the integer exit status.
-//
-// For convenience, you can get this value directly as an integer by calling
-// ExitStatus on the pipe.
-//
-// Even in the event of a non-zero exit status, the command's output will still
-// be available in the pipe. This is often helpful for debugging. However,
-// because String is a no-op if the pipe's error status is set, if you want
-// output you will need to reset the error status before calling String.
+// Exec creates a pipe that runs cmdLine as an external command and produces
+// its combined output (interleaving standard output and standard error). See
+// [Pipe.Exec] for error handling details.
//
-// Note that Exec can also be used as a filter, in which case the given command
-// will read from the pipe as its standard input.
-func Exec(s string) *Pipe {
- return NewPipe().Exec(s)
+// Use [Pipe.Exec] to send the contents of an existing pipe to the command's
+// standard input.
+func Exec(cmdLine string) *Pipe {
+ return NewPipe().Exec(cmdLine)
}
-// File creates a pipe that reads from the file at the specified path.
-func File(name string) *Pipe {
- p := NewPipe()
- f, err := os.Open(name)
+// File creates a pipe that reads from the file path.
+func File(path string) *Pipe {
+ f, err := os.Open(path)
if err != nil {
- return p.WithError(err)
+ return NewPipe().WithError(err)
}
- return p.WithReader(f)
+ return NewPipe().WithReader(f)
}
-// FindFiles takes a directory path and creates a pipe listing all the files in
-// the directory and its subdirectories recursively, one per line, like Unix
-// `find -type f`. If the path doesn't exist or can't be read, the pipe's error
-// status will be set.
+// FindFiles creates a pipe listing all the files in the directory dir and its
+// subdirectories recursively, one per line, like Unix find(1). If dir doesn't
+// exist or can't be read, the pipe's error status will be set.
+//
+// Each line of the output consists of a slash-separated path, starting with
+// the initial directory. For example, if the directory looks like this:
+//
+// test/
+// 1.txt
+// 2.txt
//
-// Each line of the output consists of a slash-separated pathname, starting with
-// the initial directory. For example, if the starting directory is "test", and
-// it contains 1.txt and 2.txt:
+// the pipe's output will be:
//
-// test/1.txt
-// test/2.txt
-func FindFiles(path string) *Pipe {
- var fileNames []string
- walkFn := func(path string, info os.FileInfo, err error) error {
+// test/1.txt
+// test/2.txt
+func FindFiles(dir string) *Pipe {
+ var paths []string
+ err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
- fileNames = append(fileNames, path)
+ paths = append(paths, path)
}
return nil
- }
- if err := filepath.Walk(path, walkFn); err != nil {
+ })
+ if err != nil {
return NewPipe().WithError(err)
}
- return Slice(fileNames)
+ return Slice(paths)
+}
+
+// Get creates a pipe that makes an HTTP GET request to URL, and produces the
+// response. See [Pipe.Do] for how the HTTP response status is interpreted.
+func Get(URL string) *Pipe {
+ return NewPipe().Get(URL)
}
-// IfExists tests whether the specified file exists, and creates a pipe whose
-// error status reflects the result. If the file doesn't exist, the pipe's error
-// status will be set, and if the file does exist, the pipe will have no error
-// status. This can be used to do some operation only if a given file exists:
+// IfExists tests whether path exists, and creates a pipe whose error status
+// reflects the result. If the file doesn't exist, the pipe's error status will
+// be set, and if the file does exist, the pipe will have no error status. This
+// can be used to do some operation only if a given file exists:
//
-// IfExists("/foo/bar").Exec("/usr/bin/something")
-func IfExists(filename string) *Pipe {
- p := NewPipe()
- _, err := os.Stat(filename)
+// IfExists("/foo/bar").Exec("/usr/bin/something")
+func IfExists(path string) *Pipe {
+ _, err := os.Stat(path)
if err != nil {
- return p.WithError(err)
+ return NewPipe().WithError(err)
}
- return p
+ return NewPipe()
}
-// ListFiles creates a pipe containing the files and directories matching the
-// supplied path, one per line. The path can be the name of a directory
-// (`/path/to/dir`), the name of a file (`/path/to/file`), or a glob (wildcard
-// expression) conforming to the syntax accepted by filepath.Match (for example
-// `/path/to/*`).
+// ListFiles creates a pipe containing the files or directories specified by
+// path, one per line. path can be a glob expression, as for [filepath.Match].
+// For example:
//
-// ListFiles does not recurse into subdirectories (use FindFiles for this).
+// ListFiles("/data/*").Stdout()
+//
+// ListFiles does not recurse into subdirectories; use [FindFiles] instead.
func ListFiles(path string) *Pipe {
if strings.ContainsAny(path, "[]^*?\\{}!") {
fileNames, err := filepath.Glob(path)
@@ -266,7 +139,7 @@ func ListFiles(path string) *Pipe {
}
return Slice(fileNames)
}
- files, err := os.ReadDir(path)
+ entries, err := os.ReadDir(path)
if err != nil {
// Check for the case where the path matches exactly one file
s, err := os.Stat(path)
@@ -278,40 +151,80 @@ func ListFiles(path string) *Pipe {
}
return NewPipe().WithError(err)
}
- fileNames := make([]string, len(files))
- for i, f := range files {
- fileNames[i] = filepath.Join(path, f.Name())
+ matches := make([]string, len(entries))
+ for i, e := range entries {
+ matches[i] = filepath.Join(path, e.Name())
}
- return Slice(fileNames)
+ return Slice(matches)
}
-// Slice creates a pipe containing each element of the supplied slice of
-// strings, one per line.
+// NewPipe creates a new pipe with an empty reader (use [Pipe.WithReader] to
+// attach another reader to it).
+func NewPipe() *Pipe {
+ return &Pipe{
+ Reader: ReadAutoCloser{},
+ mu: new(sync.Mutex),
+ stdout: os.Stdout,
+ httpClient: http.DefaultClient,
+ }
+}
+
+// Post creates a pipe that makes an HTTP POST request to URL, with an empty
+// body, and produces the response. See [Pipe.Do] for how the HTTP response
+// status is interpreted.
+func Post(URL string) *Pipe {
+ return NewPipe().Post(URL)
+}
+
+// Slice creates a pipe containing each element of s, one per line.
func Slice(s []string) *Pipe {
return Echo(strings.Join(s, "\n") + "\n")
}
-// Stdin creates a pipe that reads from os.Stdin.
+// Stdin creates a pipe that reads from [os.Stdin].
func Stdin() *Pipe {
return NewPipe().WithReader(os.Stdin)
}
-// Basename reads a list of filepaths from the pipe, one per line, and removes
-// any leading directory components from each line. So, for example,
-// `/usr/local/bin/foo` would become just `foo`. This is the complementary
-// operation to Dirname.
+// AppendFile appends the contents of the pipe to the file path, creating it if
+// necessary, and returns the number of bytes successfully written, or an
+// error.
+func (p *Pipe) AppendFile(path string) (int64, error) {
+ return p.writeOrAppendFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY)
+}
+
+// Basename reads paths from the pipe, one per line, and removes any leading
+// directory components from each. So, for example, /usr/local/bin/foo would
+// become just foo. This is the complementary operation to [Pipe.Dirname].
//
-// If a line is empty, Basename will produce '.'. Trailing slashes are removed.
-// The behaviour of Basename is the same as filepath.Base (not by coincidence).
+// If any line is empty, Basename will transform it to a single dot. Trailing
+// slashes are removed. The behaviour of Basename is the same as
+// [filepath.Base] (not by coincidence).
func (p *Pipe) Basename() *Pipe {
return p.FilterLine(filepath.Base)
}
-// Column produces only the Nth column of each line of input, where '1' is the
-// first column, and columns are delimited by whitespace. Specifically, whatever
-// Unicode defines as whitespace ('WSpace=yes').
-//
-// Lines containing less than N columns will be dropped altogether.
+// Bytes returns the contents of the pipe as a []byte, or an error.
+func (p *Pipe) Bytes() ([]byte, error) {
+ if p.Error() != nil {
+ return nil, p.Error()
+ }
+ data, err := io.ReadAll(p)
+ if err != nil {
+ p.SetError(err)
+ }
+ return data, p.Error()
+}
+
+// Close closes the pipe's associated reader. This is a no-op if the reader is
+// not an [io.Closer].
+func (p *Pipe) Close() error {
+ return p.Reader.Close()
+}
+
+// Column produces column col of each line of input, where the first column is
+// column 1, and columns are delimited by Unicode whitespace. Lines containing
+// fewer than col columns will be skipped.
func (p *Pipe) Column(col int) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
columns := strings.Fields(line)
@@ -321,48 +234,55 @@ func (p *Pipe) Column(col int) *Pipe {
})
}
-// Concat reads a list of file paths from the pipe, one per line, and produces
-// the contents of all those files in sequence. If there are any errors (for
-// example, non-existent files), these will be ignored, execution will continue,
-// and the pipe's error status will not be set.
+// Concat reads paths from the pipe, one per line, and produces the contents of
+// all the corresponding files in sequence. If there are any errors (for
+// example, non-existent files), these will be ignored, execution will
+// continue, and the pipe's error status will not be set.
//
-// This makes it convenient to write programs that take a list of input files on
-// the command line. For example:
+// This makes it convenient to write programs that take a list of paths on the
+// command line. For example:
//
-// script.Args().Concat().Stdout()
+// script.Args().Concat().Stdout()
//
-// The list of files could also come from a file:
+// The list of paths could also come from a file:
//
-// script.File("filelist.txt").Concat()
+// script.File("filelist.txt").Concat()
//
-// ...or from the output of a command:
+// Or from the output of a command:
//
-// script.Exec("ls /var/app/config/").Concat().Stdout()
+// script.Exec("ls /var/app/config/").Concat().Stdout()
//
// Each input file will be closed once it has been fully read. If any of the
-// files can't be opened or read, `Concat` will simply skip these and carry on,
+// files can't be opened or read, Concat will simply skip these and carry on,
// without setting the pipe's error status. This mimics the behaviour of Unix
-// `cat`.
+// cat(1).
func (p *Pipe) Concat() *Pipe {
var readers []io.Reader
p.FilterScan(func(line string, w io.Writer) {
input, err := os.Open(line)
- if err != nil {
- return // skip errors
+ if err == nil {
+ readers = append(readers, NewReadAutoCloser(input))
}
- readers = append(readers, NewReadAutoCloser(input))
}).Wait()
return p.WithReader(io.MultiReader(readers...))
}
-// Dirname reads a list of pathnames from the pipe, one per line, and produces
-// only the parent directories of each pathname. For example,
-// `/usr/local/bin/foo` would become just `/usr/local/bin`. This is the
-// complementary operation to Basename.
+// CountLines returns the number of lines of input, or an error.
+func (p *Pipe) CountLines() (lines int, err error) {
+ p.FilterScan(func(line string, w io.Writer) {
+ lines++
+ }).Wait()
+ return lines, p.Error()
+}
+
+// Dirname reads paths from the pipe, one per line, and produces only the
+// parent directories of each path. For example, /usr/local/bin/foo would
+// become just /usr/local/bin. This is the complementary operation to
+// [Pipe.Basename].
//
-// If a line is empty, Dirname will produce a '.'. Trailing slashes are removed,
-// unless Dirname returns the root folder. Otherwise, the behaviour of Dirname
-// is the same as filepath.Dir (not by coincidence).
+// If a line is empty, Dirname will transform it to a single dot. Trailing
+// slashes are removed, unless Dirname returns the root folder. Otherwise, the
+// behaviour of Dirname is the same as [filepath.Dir] (not by coincidence).
func (p *Pipe) Dirname() *Pipe {
return p.FilterLine(func(line string) string {
// filepath.Dir() does not handle trailing slashes correctly
@@ -378,131 +298,213 @@ func (p *Pipe) Dirname() *Pipe {
})
}
-// EachLine calls the specified function for each line of input, passing it the
-// line as a string, and a *strings.Builder to write its output to.
+// Do performs the HTTP request req using the pipe's configured HTTP client, as
+// set by [Pipe.WithHTTPClient], or [http.DefaultClient] otherwise. The
+// response body is streamed concurrently to the pipe's output. If the response
+// status is anything other than HTTP 200-299, the pipe's error status is set.
+func (p *Pipe) Do(req *http.Request) *Pipe {
+ return p.Filter(func(r io.Reader, w io.Writer) error {
+ resp, err := p.httpClient.Do(req)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ _, err = io.Copy(w, resp.Body)
+ if err != nil {
+ return err
+ }
+ // Any HTTP 2xx status code is considered okay
+ if resp.StatusCode/100 != 2 {
+ return fmt.Errorf("unexpected HTTP response status: %s", resp.Status)
+ }
+ return nil
+ })
+}
+
+// EachLine calls the function process on each line of input, passing it the
+// line as a string, and a [*strings.Builder] to write its output to.
//
-// Deprecated: use FilterLine or FilterScan instead, which run concurrently and
-// don't do unnecessary reads on the input.
+// Deprecated: use [Pipe.FilterLine] or [Pipe.FilterScan] instead, which run
+// concurrently and don't do unnecessary reads on the input.
func (p *Pipe) EachLine(process func(string, *strings.Builder)) *Pipe {
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
- output := strings.Builder{}
+ scanner := newScanner(r)
+ output := new(strings.Builder)
for scanner.Scan() {
- process(scanner.Text(), &output)
+ process(scanner.Text(), output)
}
fmt.Fprint(w, output.String())
return scanner.Err()
})
}
-// Echo produces the supplied string.
+// Echo sets the pipe's reader to one that produces the string s, detaching any
+// existing reader without draining or closing it.
func (p *Pipe) Echo(s string) *Pipe {
if p.Error() != nil {
return p
}
- return p.WithReader(NewReadAutoCloser(strings.NewReader(s)))
+ return p.WithReader(strings.NewReader(s))
}
-// Exec runs an external command, sending it the contents of the pipe as input,
-// and produces the command's combined output (`stdout` and `stderr`). The
-// effect of this is to filter the contents of the pipe through the external
-// command.
+// Error returns any error present on the pipe, or nil otherwise.
+func (p *Pipe) Error() error {
+ if p.mu == nil { // uninitialised pipe
+ return nil
+ }
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ return p.err
+}
+
+// Exec runs cmdLine as an external command, sending it the contents of the
+// pipe as input, and produces the command's standard output (see below for
+// error output). The effect of this is to filter the contents of the pipe
+// through the external command.
+//
+// # Error handling
//
// If the command had a non-zero exit status, the pipe's error status will also
-// be set to the string "exit status X", where X is the integer exit status.
-func (p *Pipe) Exec(command string) *Pipe {
+// be set to the string “exit status X”, where X is the integer exit status.
+// Even in the event of a non-zero exit status, the command's output will still
+// be available in the pipe. This is often helpful for debugging. However,
+// because [Pipe.String] is a no-op if the pipe's error status is set, if you
+// want output you will need to reset the error status before calling
+// [Pipe.String].
+//
+// If the command writes to its standard error stream, this will also go to the
+// pipe, along with its standard output. However, the standard error text can
+// instead be redirected to a supplied writer, using [Pipe.WithStderr].
+func (p *Pipe) Exec(cmdLine string) *Pipe {
return p.Filter(func(r io.Reader, w io.Writer) error {
- args, ok := shell.Split(command) // strings.Fields doesn't handle quotes
- if !ok {
- return fmt.Errorf("unbalanced quotes or backslashes in [%s]", command)
+ args, err := shell.Fields(cmdLine, nil)
+ if err != nil {
+ return err
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdin = r
cmd.Stdout = w
cmd.Stderr = w
- err := cmd.Start()
+ if p.stderr != nil {
+ cmd.Stderr = p.stderr
+ }
+ err = cmd.Start()
if err != nil {
- fmt.Fprintln(w, err)
+ fmt.Fprintln(cmd.Stderr, err)
return err
}
return cmd.Wait()
})
}
-// ExecForEach runs the supplied command once for each line of input, and
-// produces its combined output. The command string is interpreted as a Go
-// template, so `{{.}}` will be replaced with the input value, for example.
+// ExecForEach renders cmdLine as a Go template for each line of input, running
+// the resulting command, and produces the combined output of all these
+// commands in sequence. See [Pipe.Exec] for error handling details.
//
-// If any command resulted in a non-zero exit status, the pipe's error status
-// will also be set to the string "exit status X", where X is the integer exit
-// status.
-func (p *Pipe) ExecForEach(command string) *Pipe {
- if p.Error() != nil {
- return p
- }
- tpl, err := template.New("").Parse(command)
+// This is mostly useful for substituting data into commands using Go template
+// syntax. For example:
+//
+// ListFiles("*").ExecForEach("touch {{.}}").Wait()
+func (p *Pipe) ExecForEach(cmdLine string) *Pipe {
+ tpl, err := template.New("").Parse(cmdLine)
if err != nil {
return p.WithError(err)
}
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
+ scanner := newScanner(r)
for scanner.Scan() {
- cmdLine := strings.Builder{}
- err := tpl.Execute(&cmdLine, scanner.Text())
+ cmdLine := new(strings.Builder)
+ err := tpl.Execute(cmdLine, scanner.Text())
if err != nil {
return err
}
- args, ok := shell.Split(cmdLine.String()) // strings.Fields doesn't handle quotes
- if !ok {
- return fmt.Errorf("unbalanced quotes or backslashes in [%s]", cmdLine.String())
+ args, err := shell.Fields(cmdLine.String(), nil)
+ if err != nil {
+ return err
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = w
cmd.Stderr = w
+ if p.stderr != nil {
+ cmd.Stderr = p.stderr
+ }
err = cmd.Start()
if err != nil {
- fmt.Fprintln(w, err)
+ fmt.Fprintln(cmd.Stderr, err)
+ continue
+ }
+ err = cmd.Wait()
+ if err != nil {
+ fmt.Fprintln(cmd.Stderr, err)
continue
}
- cmd.Wait()
}
return scanner.Err()
})
}
-// Filter filters the contents of the pipe through the supplied function, which
-// takes an io.Reader (the filter input) and an io.Writer (the filter output),
-// and returns an error, which will be set on the pipe.
+var exitStatusPattern = regexp.MustCompile(`exit status (\d+)$`)
+
+// ExitStatus returns the integer exit status of a previous command (for
+// example run by [Pipe.Exec]). This will be zero unless the pipe's error
+// status is set and the error matches the pattern “exit status %d”.
+func (p *Pipe) ExitStatus() int {
+ if p.Error() == nil {
+ return 0
+ }
+ match := exitStatusPattern.FindStringSubmatch(p.Error().Error())
+ if len(match) < 2 {
+ return 0
+ }
+ status, err := strconv.Atoi(match[1])
+ if err != nil {
+ // This seems unlikely, but...
+ return 0
+ }
+ return status
+}
+
+// Filter sends the contents of the pipe to the function filter and produces
+// the result. filter takes an [io.Reader] to read its input from and an
+// [io.Writer] to write its output to, and returns an error, which will be set
+// on the pipe.
//
-// The filter function runs concurrently, so its goroutine will not complete
-// until the pipe has been fully read. If you just need to make sure all
-// concurrent filters have completed, call Wait on the end of the pipe.
+// filter runs concurrently, so its goroutine will not exit until the pipe has
+// been fully read. Use [Pipe.Wait] to wait for all concurrent filters to
+// complete.
func (p *Pipe) Filter(filter func(io.Reader, io.Writer) error) *Pipe {
+ if p.Error() != nil {
+ return p
+ }
pr, pw := io.Pipe()
- q := NewPipe().WithReader(pr)
+ origReader := p.Reader
+ p = p.WithReader(pr)
go func() {
defer pw.Close()
- err := filter(p, pw)
- q.SetError(err)
+ err := filter(origReader, pw)
+ if err != nil {
+ p.SetError(err)
+ }
}()
- return q
+ return p
}
-// FilterLine filters the contents of the pipe, a line at a time, through the
-// supplied function, which takes the line as a string and returns a string (the
-// filter output). The filter function runs concurrently.
+// FilterLine sends the contents of the pipe to the function filter, a line at
+// a time, and produces the result. filter takes each line as a string and
+// returns a string as its output. See [Pipe.Filter] for concurrency handling.
func (p *Pipe) FilterLine(filter func(string) string) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
fmt.Fprintln(w, filter(line))
})
}
-// FilterScan filters the contents of the pipe, a line at a time, through the
-// supplied function, which takes the line as a string and an io.Writer (the
-// filtero output). The filter function runs concurrently.
+// FilterScan sends the contents of the pipe to the function filter, a line at
+// a time, and produces the result. filter takes each line as a string and an
+// [io.Writer] to write its output to. See [Pipe.Filter] for concurrency
+// handling.
func (p *Pipe) FilterScan(filter func(string, io.Writer)) *Pipe {
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
+ scanner := newScanner(r)
for scanner.Scan() {
filter(scanner.Text(), w)
}
@@ -510,9 +512,13 @@ func (p *Pipe) FilterScan(filter func(string, io.Writer)) *Pipe {
})
}
-// First produces only the first N lines of input, or the whole input if there
-// are less than N lines. If N is zero or negative, there is no output at all.
+// First produces only the first n lines of the pipe's contents, or all the
+// lines if there are less than n. If n is zero or negative, there is no output
+// at all.
func (p *Pipe) First(n int) *Pipe {
+ if p.Error() != nil {
+ return p
+ }
if n <= 0 {
return NewPipe()
}
@@ -526,28 +532,24 @@ func (p *Pipe) First(n int) *Pipe {
})
}
-// Freq produces only unique lines from the input, prefixed with a frequency
-// count, in descending numerical order (most frequent lines first). Lines with
-// equal frequency will be sorted alphabetically.
+// Freq produces only the unique lines from the pipe's contents, each prefixed
+// with a frequency count, in descending numerical order (most frequent lines
+// first). Lines with equal frequency will be sorted alphabetically.
//
-// This is a common pattern in shell scripts to find the most
-// frequently-occurring lines in a file:
+// For example, we could take a common shell pipeline like this:
//
-// sort testdata/freq.input.txt |uniq -c |sort -rn
+// sort input.txt |uniq -c |sort -rn
//
-// Freq's behaviour is like the combination of Unix `sort`, `uniq -c`, and `sort
-// -rn` used here. You can use Freq in combination with First to get, for
-// example, the ten most common lines in a file:
+// and replace it with:
//
-// script.Stdin().Freq().First(10).Stdout()
+// File("input.txt").Freq().Stdout()
//
-// Like `uniq -c`, Freq left-pads its count values if necessary to make them
-// easier to read:
+// Or to get only the ten most common lines:
//
-// 10 apple
-// 4 banana
-// 2 orange
-// 1 kumquat
+// File("input.txt").Freq().First(10).Stdout()
+//
+// Like Unix uniq(1), Freq right-justifies its count values in a column for
+// readability, padding with spaces if necessary.
func (p *Pipe) Freq() *Pipe {
freq := map[string]int{}
type frequency struct {
@@ -555,16 +557,16 @@ func (p *Pipe) Freq() *Pipe {
count int
}
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
+ scanner := newScanner(r)
for scanner.Scan() {
freq[scanner.Text()]++
}
freqs := make([]frequency, 0, len(freq))
- var maxCount int
+ max := 0
for line, count := range freq {
freqs = append(freqs, frequency{line, count})
- if count > maxCount {
- maxCount = count
+ if count > max {
+ max = count
}
}
sort.Slice(freqs, func(i, j int) bool {
@@ -574,7 +576,7 @@ func (p *Pipe) Freq() *Pipe {
}
return x > y
})
- fieldWidth := len(strconv.Itoa(maxCount))
+ fieldWidth := len(strconv.Itoa(max))
for _, item := range freqs {
fmt.Fprintf(w, "%*d %s\n", fieldWidth, item.count, item.line)
}
@@ -582,18 +584,28 @@ func (p *Pipe) Freq() *Pipe {
})
}
-// Join produces its input as a single space-separated string, which will always
-// end with a newline.
+// Get makes an HTTP GET request to URL, sending the contents of the pipe as
+// the request body, and produces the server's response. See [Pipe.Do] for how
+// the HTTP response status is interpreted.
+func (p *Pipe) Get(URL string) *Pipe {
+ req, err := http.NewRequest(http.MethodGet, URL, p.Reader)
+ if err != nil {
+ return p.WithError(err)
+ }
+ return p.Do(req)
+}
+
+// Join joins all the lines in the pipe's contents into a single
+// space-separated string, which will always end with a newline.
func (p *Pipe) Join() *Pipe {
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
- var line string
+ scanner := newScanner(r)
first := true
for scanner.Scan() {
if !first {
fmt.Fprint(w, " ")
}
- line = scanner.Text()
+ line := scanner.Text()
fmt.Fprint(w, line)
first = false
}
@@ -602,13 +614,12 @@ func (p *Pipe) Join() *Pipe {
})
}
-// JQ takes a query in the 'jq' language and applies it to the input (presumed
-// to be JSON), producing the result. An invalid query will set the appropriate
-// error on the pipe.
+// JQ executes query on the pipe's contents (presumed to be JSON), producing
+// the result. An invalid query will set the appropriate error on the pipe.
//
// The exact dialect of JQ supported is that provided by
-// github.com/itchyny/gojq, whose documentation explains the differences between
-// it and 'standard' JQ.
+// [github.com/itchyny/gojq], whose documentation explains the differences
+// between it and standard JQ.
func (p *Pipe) JQ(query string) *Pipe {
return p.Filter(func(r io.Reader, w io.Writer) error {
q, err := gojq.Parse(query)
@@ -638,14 +649,18 @@ func (p *Pipe) JQ(query string) *Pipe {
})
}
-// Last produces only the last N lines of input, or the whole input if there are
-// less than N lines. If N is zero or negative, there is no output at all.
+// Last produces only the last n lines of the pipe's contents, or all the lines
+// if there are less than n. If n is zero or negative, there is no output at
+// all.
func (p *Pipe) Last(n int) *Pipe {
+ if p.Error() != nil {
+ return p
+ }
if n <= 0 {
return NewPipe()
}
return p.Filter(func(r io.Reader, w io.Writer) error {
- scanner := bufio.NewScanner(r)
+ scanner := newScanner(r)
input := ring.New(n)
for scanner.Scan() {
input.Value = scanner.Text()
@@ -660,7 +675,7 @@ func (p *Pipe) Last(n int) *Pipe {
})
}
-// Match produces only lines that contain the specified string.
+// Match produces only the input lines that contain the string s.
func (p *Pipe) Match(s string) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
if strings.Contains(line, s) {
@@ -669,8 +684,7 @@ func (p *Pipe) Match(s string) *Pipe {
})
}
-// MatchRegexp produces only lines that match the specified compiled regular
-// expression.
+// MatchRegexp produces only the input lines that match the compiled regexp re.
func (p *Pipe) MatchRegexp(re *regexp.Regexp) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
if re.MatchString(line) {
@@ -679,7 +693,18 @@ func (p *Pipe) MatchRegexp(re *regexp.Regexp) *Pipe {
})
}
-// Reject produces only lines that do not contain the specified string.
+// Post makes an HTTP POST request to URL, using the contents of the pipe as
+// the request body, and produces the server's response. See [Pipe.Do] for how
+// the HTTP response status is interpreted.
+func (p *Pipe) Post(URL string) *Pipe {
+ req, err := http.NewRequest(http.MethodPost, URL, p.Reader)
+ if err != nil {
+ return p.WithError(err)
+ }
+ return p.Do(req)
+}
+
+// Reject produces only lines that do not contain the string s.
func (p *Pipe) Reject(s string) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
if !strings.Contains(line, s) {
@@ -688,8 +713,7 @@ func (p *Pipe) Reject(s string) *Pipe {
})
}
-// RejectRegexp produces only lines that don't match the specified compiled
-// regular expression.
+// RejectRegexp produces only lines that don't match the compiled regexp re.
func (p *Pipe) RejectRegexp(re *regexp.Regexp) *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
if !re.MatchString(line) {
@@ -698,27 +722,61 @@ func (p *Pipe) RejectRegexp(re *regexp.Regexp) *Pipe {
})
}
-// Replace replaces all occurrences of the 'search' string with the 'replace'
-// string.
+// Replace replaces all occurrences of the string search with the string
+// replace.
func (p *Pipe) Replace(search, replace string) *Pipe {
return p.FilterLine(func(line string) string {
return strings.ReplaceAll(line, search, replace)
})
}
-// ReplaceRegexp replaces all matches of the specified compiled regular
-// expression with the 'replace' string. '$' characters in the replace string
-// are interpreted as in regexp.Expand; for example, "$1" represents the text of
-// the first submatch.
+// ReplaceRegexp replaces all matches of the compiled regexp re with the string
+// re. $x variables in the replace string are interpreted as by
+// [regexp.Expand]; for example, $1 represents the text of the first submatch.
func (p *Pipe) ReplaceRegexp(re *regexp.Regexp, replace string) *Pipe {
return p.FilterLine(func(line string) string {
return re.ReplaceAllString(line, replace)
})
}
-// SHA256Sums reads a list of file paths from the pipe, one per line, and
-// produces the hex-encoded SHA-256 hash of each file. Any files that cannot be
-// opened or read will be ignored.
+// Read reads up to len(b) bytes from the pipe into b. It returns the number of
+// bytes read and any error encountered. At end of file, or on a nil pipe, Read
+// returns 0, [io.EOF].
+func (p *Pipe) Read(b []byte) (int, error) {
+ if p.Error() != nil {
+ return 0, p.Error()
+ }
+ return p.Reader.Read(b)
+}
+
+// SetError sets the error err on the pipe.
+func (p *Pipe) SetError(err error) {
+ if p.mu == nil { // uninitialised pipe
+ return
+ }
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ p.err = err
+}
+
+// SHA256Sum returns the hex-encoded SHA-256 hash of the entire contents of the
+// pipe, or an error.
+func (p *Pipe) SHA256Sum() (string, error) {
+ if p.Error() != nil {
+ return "", p.Error()
+ }
+ hasher := sha256.New()
+ _, err := io.Copy(hasher, p)
+ if err != nil {
+ p.SetError(err)
+ return "", err
+ }
+ return hex.EncodeToString(hasher.Sum(nil)), p.Error()
+}
+
+// SHA256Sums reads paths from the pipe, one per line, and produces the
+// hex-encoded SHA-256 hash of each corresponding file, one per line. Any files
+// that cannot be opened or read will be ignored.
func (p *Pipe) SHA256Sums() *Pipe {
return p.FilterScan(func(line string, w io.Writer) {
f, err := os.Open(line)
@@ -735,48 +793,12 @@ func (p *Pipe) SHA256Sums() *Pipe {
})
}
-// AppendFile appends the contents of the pipe to the specified file, and
-// returns the number of bytes successfully written, or an error. If the file
-// does not exist, it is created.
-func (p *Pipe) AppendFile(fileName string) (int64, error) {
- return p.writeOrAppendFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY)
-}
-
-// Bytes returns the contents of the pipe as a []]byte, or an error.
-func (p *Pipe) Bytes() ([]byte, error) {
- res, err := io.ReadAll(p)
- if err != nil {
- p.SetError(err)
- }
- return res, err
-}
-
-// CountLines returns the number of lines of input, or an error.
-func (p *Pipe) CountLines() (int, error) {
- lines := 0
- p.FilterScan(func(line string, w io.Writer) {
- lines++
- }).Wait()
- return lines, p.Error()
-}
-
-// SHA256Sum returns the hex-encoded SHA-256 hash of its input, or an error.
-func (p *Pipe) SHA256Sum() (string, error) {
- hasher := sha256.New()
- _, err := io.Copy(hasher, p)
- if err != nil {
- p.SetError(err)
- return "", err
- }
- return hex.EncodeToString(hasher.Sum(nil)), p.Error()
-}
-
-// Slice returns the input as a slice of strings, one element per line, or an
-// error.
+// Slice returns the pipe's contents as a slice of strings, one element per
+// line, or an error.
//
// An empty pipe will produce an empty slice. A pipe containing a single empty
-// line (that is, a single `\n` character) will produce a slice containing the
-// empty string.
+// line (that is, a single \n character) will produce a slice containing the
+// empty string as its single element.
func (p *Pipe) Slice() ([]string, error) {
result := []string{}
p.FilterScan(func(line string, w io.Writer) {
@@ -785,9 +807,13 @@ func (p *Pipe) Slice() ([]string, error) {
return result, p.Error()
}
-// Stdout writes the input to the pipe's configured standard output, and returns
-// the number of bytes successfully written, or an error.
+// Stdout copies the pipe's contents to its configured standard output (using
+// [Pipe.WithStdout]), or to [os.Stdout] otherwise, and returns the number of
+// bytes successfully written, together with any error.
func (p *Pipe) Stdout() (int, error) {
+ if p.Error() != nil {
+ return 0, p.Error()
+ }
n64, err := io.Copy(p.stdout, p)
if err != nil {
return 0, err
@@ -799,7 +825,7 @@ func (p *Pipe) Stdout() (int, error) {
return n, p.Error()
}
-// String returns the input as a string, or an error.
+// String returns the pipe's contents as a string, together with any error.
func (p *Pipe) String() (string, error) {
data, err := p.Bytes()
if err != nil {
@@ -808,24 +834,78 @@ func (p *Pipe) String() (string, error) {
return string(data), p.Error()
}
-// Wait reads the input to completion and discards it. This is mostly useful for
-// waiting until all concurrent filter stages have finished.
+// Tee copies the pipe's contents to each of the supplied writers, like Unix
+// tee(1). If no writers are supplied, the default is the pipe's standard
+// output.
+func (p *Pipe) Tee(writers ...io.Writer) *Pipe {
+ teeWriter := p.stdout
+ if len(writers) > 0 {
+ teeWriter = io.MultiWriter(writers...)
+ }
+ return p.WithReader(io.TeeReader(p.Reader, teeWriter))
+}
+
+// Wait reads the pipe to completion and discards the result. This is mostly
+// useful for waiting until concurrent filters have completed (see
+// [Pipe.Filter]).
func (p *Pipe) Wait() {
- _, err := io.Copy(io.Discard, p)
+ _, err := io.ReadAll(p)
if err != nil {
p.SetError(err)
}
}
-// WriteFile writes the input to the specified file, and returns the number of
-// bytes successfully written, or an error. If the file already exists, it is
-// truncated and the new data will replace the old.
-func (p *Pipe) WriteFile(fileName string) (int64, error) {
- return p.writeOrAppendFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
+// WithError sets the error err on the pipe.
+func (p *Pipe) WithError(err error) *Pipe {
+ p.SetError(err)
+ return p
+}
+
+// WithHTTPClient sets the HTTP client c for use with subsequent requests via
+// [Pipe.Do], [Pipe.Get], or [Pipe.Post]. For example, to make a request using
+// a client with a timeout:
+//
+// NewPipe().WithHTTPClient(&http.Client{
+// Timeout: 10 * time.Second,
+// }).Get("https://example.com").Stdout()
+func (p *Pipe) WithHTTPClient(c *http.Client) *Pipe {
+ p.httpClient = c
+ return p
+}
+
+// WithReader sets the pipe's input reader to r. Once r has been completely
+// read, it will be closed if necessary.
+func (p *Pipe) WithReader(r io.Reader) *Pipe {
+ p.Reader = NewReadAutoCloser(r)
+ return p
+}
+
+// WithStderr redirects the standard error output for commands run via
+// [Pipe.Exec] or [Pipe.ExecForEach] to the writer w, instead of going to the
+// pipe as it normally would.
+func (p *Pipe) WithStderr(w io.Writer) *Pipe {
+ p.stderr = w
+ return p
}
-func (p *Pipe) writeOrAppendFile(fileName string, mode int) (int64, error) {
- out, err := os.OpenFile(fileName, mode, 0666)
+// WithStdout sets the pipe's standard output to the writer w, instead of the
+// default [os.Stdout].
+func (p *Pipe) WithStdout(w io.Writer) *Pipe {
+ p.stdout = w
+ return p
+}
+
+// WriteFile writes the pipe's contents to the file path, truncating it if it
+// exists, and returns the number of bytes successfully written, or an error.
+func (p *Pipe) WriteFile(path string) (int64, error) {
+ return p.writeOrAppendFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
+}
+
+func (p *Pipe) writeOrAppendFile(path string, mode int) (int64, error) {
+ if p.Error() != nil {
+ return 0, p.Error()
+ }
+ out, err := os.OpenFile(path, mode, 0666)
if err != nil {
p.SetError(err)
return 0, err
@@ -834,7 +914,53 @@ func (p *Pipe) writeOrAppendFile(fileName string, mode int) (int64, error) {
wrote, err := io.Copy(out, p)
if err != nil {
p.SetError(err)
- return 0, err
}
- return wrote, nil
+ return wrote, p.Error()
+}
+
+// ReadAutoCloser wraps an [io.ReadCloser] so that it will be automatically
+// closed once it has been fully read.
+type ReadAutoCloser struct {
+ r io.ReadCloser
+}
+
+// NewReadAutoCloser returns a [ReadAutoCloser] wrapping the reader r.
+func NewReadAutoCloser(r io.Reader) ReadAutoCloser {
+ if _, ok := r.(io.Closer); !ok {
+ return ReadAutoCloser{io.NopCloser(r)}
+ }
+ rc, ok := r.(io.ReadCloser)
+ if !ok {
+ // This can never happen, but just in case it does...
+ panic("internal error: type assertion to io.ReadCloser failed")
+ }
+ return ReadAutoCloser{rc}
+}
+
+// Close closes ra's reader, returning any resulting error.
+func (ra ReadAutoCloser) Close() error {
+ if ra.r == nil {
+ return nil
+ }
+ return ra.r.(io.Closer).Close()
+}
+
+// Read reads up to len(b) bytes from ra's reader into b. It returns the number
+// of bytes read and any error encountered. At end of file, Read returns 0,
+// [io.EOF]. If end-of-file is reached, the reader will be closed.
+func (ra ReadAutoCloser) Read(b []byte) (n int, err error) {
+ if ra.r == nil {
+ return 0, io.EOF
+ }
+ n, err = ra.r.Read(b)
+ if err == io.EOF {
+ ra.Close()
+ }
+ return n, err
+}
+
+func newScanner(r io.Reader) *bufio.Scanner {
+ scanner := bufio.NewScanner(r)
+ scanner.Buffer(make([]byte, 4096), math.MaxInt)
+ return scanner
}
diff --git a/vendor/github.com/dustin/go-humanize/.travis.yml b/vendor/github.com/dustin/go-humanize/.travis.yml
index ba95cdd1..ac12e485 100644
--- a/vendor/github.com/dustin/go-humanize/.travis.yml
+++ b/vendor/github.com/dustin/go-humanize/.travis.yml
@@ -1,12 +1,12 @@
sudo: false
language: go
+go_import_path: github.com/dustin/go-humanize
go:
- - 1.3.x
- - 1.5.x
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
+ - 1.13.x
+ - 1.14.x
+ - 1.15.x
+ - 1.16.x
+ - stable
- master
matrix:
allow_failures:
@@ -15,7 +15,7 @@ matrix:
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- - go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- - go tool vet .
+ - go vet .
+ - go install -v -race ./...
- go test -v -race ./...
diff --git a/vendor/github.com/dustin/go-humanize/README.markdown b/vendor/github.com/dustin/go-humanize/README.markdown
index 91b4ae56..7d0b16b3 100644
--- a/vendor/github.com/dustin/go-humanize/README.markdown
+++ b/vendor/github.com/dustin/go-humanize/README.markdown
@@ -5,7 +5,7 @@ Just a few functions for helping humanize times and sizes.
`go get` it as `github.com/dustin/go-humanize`, import it as
`"github.com/dustin/go-humanize"`, use it as `humanize`.
-See [godoc](https://godoc.org/github.com/dustin/go-humanize) for
+See [godoc](https://pkg.go.dev/github.com/dustin/go-humanize) for
complete documentation.
## Sizes
diff --git a/vendor/github.com/dustin/go-humanize/bigbytes.go b/vendor/github.com/dustin/go-humanize/bigbytes.go
index 1a2bf617..3b015fd5 100644
--- a/vendor/github.com/dustin/go-humanize/bigbytes.go
+++ b/vendor/github.com/dustin/go-humanize/bigbytes.go
@@ -28,6 +28,10 @@ var (
BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
// BigYiByte is 1,024 z bytes in bit.Ints
BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
+ // BigRiByte is 1,024 y bytes in bit.Ints
+ BigRiByte = (&big.Int{}).Mul(BigYiByte, bigIECExp)
+ // BigQiByte is 1,024 r bytes in bit.Ints
+ BigQiByte = (&big.Int{}).Mul(BigRiByte, bigIECExp)
)
var (
@@ -51,6 +55,10 @@ var (
BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
// BigYByte is 1,000 SI z bytes in big.Ints
BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
+ // BigRByte is 1,000 SI y bytes in big.Ints
+ BigRByte = (&big.Int{}).Mul(BigYByte, bigSIExp)
+ // BigQByte is 1,000 SI r bytes in big.Ints
+ BigQByte = (&big.Int{}).Mul(BigRByte, bigSIExp)
)
var bigBytesSizeTable = map[string]*big.Int{
@@ -71,6 +79,10 @@ var bigBytesSizeTable = map[string]*big.Int{
"zb": BigZByte,
"yib": BigYiByte,
"yb": BigYByte,
+ "rib": BigRiByte,
+ "rb": BigRByte,
+ "qib": BigQiByte,
+ "qb": BigQByte,
// Without suffix
"": BigByte,
"ki": BigKiByte,
@@ -89,6 +101,10 @@ var bigBytesSizeTable = map[string]*big.Int{
"zi": BigZiByte,
"y": BigYByte,
"yi": BigYiByte,
+ "r": BigRByte,
+ "ri": BigRiByte,
+ "q": BigQByte,
+ "qi": BigQiByte,
}
var ten = big.NewInt(10)
@@ -115,7 +131,7 @@ func humanateBigBytes(s, base *big.Int, sizes []string) string {
//
// BigBytes(82854982) -> 83 MB
func BigBytes(s *big.Int) string {
- sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
+ sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "RB", "QB"}
return humanateBigBytes(s, bigSIExp, sizes)
}
@@ -125,7 +141,7 @@ func BigBytes(s *big.Int) string {
//
// BigIBytes(82854982) -> 79 MiB
func BigIBytes(s *big.Int) string {
- sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
+ sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"}
return humanateBigBytes(s, bigIECExp, sizes)
}
diff --git a/vendor/github.com/dustin/go-humanize/commaf.go b/vendor/github.com/dustin/go-humanize/commaf.go
index 620690de..2bc83a03 100644
--- a/vendor/github.com/dustin/go-humanize/commaf.go
+++ b/vendor/github.com/dustin/go-humanize/commaf.go
@@ -1,3 +1,4 @@
+//go:build go1.6
// +build go1.6
package humanize
diff --git a/vendor/github.com/dustin/go-humanize/ftoa.go b/vendor/github.com/dustin/go-humanize/ftoa.go
index 1c62b640..bce923f3 100644
--- a/vendor/github.com/dustin/go-humanize/ftoa.go
+++ b/vendor/github.com/dustin/go-humanize/ftoa.go
@@ -6,6 +6,9 @@ import (
)
func stripTrailingZeros(s string) string {
+ if !strings.ContainsRune(s, '.') {
+ return s
+ }
offset := len(s) - 1
for offset > 0 {
if s[offset] == '.' {
diff --git a/vendor/github.com/dustin/go-humanize/number.go b/vendor/github.com/dustin/go-humanize/number.go
index dec61865..6470d0d4 100644
--- a/vendor/github.com/dustin/go-humanize/number.go
+++ b/vendor/github.com/dustin/go-humanize/number.go
@@ -73,7 +73,7 @@ func FormatFloat(format string, n float64) string {
if n > math.MaxFloat64 {
return "Infinity"
}
- if n < -math.MaxFloat64 {
+ if n < (0.0 - math.MaxFloat64) {
return "-Infinity"
}
diff --git a/vendor/github.com/dustin/go-humanize/si.go b/vendor/github.com/dustin/go-humanize/si.go
index ae659e0e..8b850198 100644
--- a/vendor/github.com/dustin/go-humanize/si.go
+++ b/vendor/github.com/dustin/go-humanize/si.go
@@ -8,6 +8,8 @@ import (
)
var siPrefixTable = map[float64]string{
+ -30: "q", // quecto
+ -27: "r", // ronto
-24: "y", // yocto
-21: "z", // zepto
-18: "a", // atto
@@ -25,6 +27,8 @@ var siPrefixTable = map[float64]string{
18: "E", // exa
21: "Z", // zetta
24: "Y", // yotta
+ 27: "R", // ronna
+ 30: "Q", // quetta
}
var revSIPrefixTable = revfmap(siPrefixTable)
diff --git a/vendor/github.com/gookit/color/README.md b/vendor/github.com/gookit/color/README.md
index 718b11b5..77d50ca3 100644
--- a/vendor/github.com/gookit/color/README.md
+++ b/vendor/github.com/gookit/color/README.md
@@ -570,6 +570,7 @@ Check out these projects, which use https://github.com/gookit/color :
- [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)
diff --git a/vendor/github.com/gookit/color/README.zh-CN.md b/vendor/github.com/gookit/color/README.zh-CN.md
index 1b144058..192a89c5 100644
--- a/vendor/github.com/gookit/color/README.zh-CN.md
+++ b/vendor/github.com/gookit/color/README.zh-CN.md
@@ -578,6 +578,7 @@ const (
## 参考项目
- [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)
diff --git a/vendor/github.com/gookit/color/any.go b/vendor/github.com/gookit/color/any.go
new file mode 100644
index 00000000..8bf31c18
--- /dev/null
+++ b/vendor/github.com/gookit/color/any.go
@@ -0,0 +1,6 @@
+//go:build !go1.18
+// +build !go1.18
+
+package color
+
+type any = interface{}
diff --git a/vendor/github.com/gookit/color/color.go b/vendor/github.com/gookit/color/color.go
index 59e0b0b6..22de1b04 100644
--- a/vendor/github.com/gookit/color/color.go
+++ b/vendor/github.com/gookit/color/color.go
@@ -183,7 +183,7 @@ func InnerErrs() []error {
// Usage:
//
// msg := RenderCode("3;32;45", "some", "message")
-func RenderCode(code string, args ...interface{}) string {
+func RenderCode(code string, args ...any) string {
var message string
if ln := len(args); ln == 0 {
return ""
@@ -205,7 +205,7 @@ func RenderCode(code string, args ...interface{}) string {
// RenderWithSpaces Render code with spaces.
// If the number of args is > 1, a space will be added between the args
-func RenderWithSpaces(code string, args ...interface{}) string {
+func RenderWithSpaces(code string, args ...any) string {
msg := formatArgsForPrintln(args)
if len(code) == 0 {
return msg
diff --git a/vendor/github.com/gookit/color/color_16.go b/vendor/github.com/gookit/color/color_16.go
index 3551521c..eda226a1 100644
--- a/vendor/github.com/gookit/color/color_16.go
+++ b/vendor/github.com/gookit/color/color_16.go
@@ -41,15 +41,27 @@ func (o Opts) String() string {
* Basic 16 color definition
*************************************************************/
-// Base value for foreground/background color
-// base: fg 30~37, bg 40~47
-// light: fg 90~97, bg 100~107
+const (
+ // OptMax max option value. range: 0 - 9
+ OptMax = 10
+ // DiffFgBg diff foreground and background color
+ DiffFgBg = 10
+)
+
+// Boundary value for foreground/background color 16
+//
+// - base: fg 30~37, bg 40~47
+// - light: fg 90~97, bg 100~107
const (
FgBase uint8 = 30
+ FgMax uint8 = 37
BgBase uint8 = 40
+ BgMax uint8 = 47
HiFgBase uint8 = 90
+ HiFgMax uint8 = 97
HiBgBase uint8 = 100
+ HiBgMax uint8 = 107
)
// Foreground colors. basic foreground colors 30 - 37
@@ -94,7 +106,7 @@ const (
BgDefault Color = 49
)
-// Extra background color 100 - 107(非标准)
+// Extra background color 100 - 107 (non-standard)
const (
BgDarkGray Color = iota + 100
BgLightRed
@@ -108,7 +120,7 @@ const (
BgGray Color = 100
)
-// Option settings
+// Option settings. range: 0 - 9
const (
OpReset Color = iota // 0 重置所有设置
OpBold // 1 加粗
@@ -188,61 +200,69 @@ func (c Color) Text(message string) string { return RenderString(c.String(), mes
// Render messages by color setting
//
// Usage:
-// green := color.FgGreen.Render
-// fmt.Println(green("message"))
-func (c Color) Render(a ...interface{}) string { return RenderCode(c.String(), a...) }
+//
+// green := color.FgGreen.Render
+// fmt.Println(green("message"))
+func (c Color) Render(a ...any) string { return RenderCode(c.String(), a...) }
// Renderln messages by color setting.
// like Println, will add spaces for each argument
//
// Usage:
-// green := color.FgGreen.Renderln
-// fmt.Println(green("message"))
-func (c Color) Renderln(a ...interface{}) string { return RenderWithSpaces(c.String(), a...) }
+//
+// green := color.FgGreen.Renderln
+// fmt.Println(green("message"))
+func (c Color) Renderln(a ...any) string { return RenderWithSpaces(c.String(), a...) }
// Sprint render messages by color setting. is alias of the Render()
-func (c Color) Sprint(a ...interface{}) string { return RenderCode(c.String(), a...) }
+func (c Color) Sprint(a ...any) string { return RenderCode(c.String(), a...) }
// Sprintf format and render message.
//
// Usage:
-// green := color.Green.Sprintf
-// colored := green("message")
-func (c Color) Sprintf(format string, args ...interface{}) string {
+//
+// green := color.Green.Sprintf
+// colored := green("message")
+func (c Color) Sprintf(format string, args ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, args...))
}
// Print messages.
//
// Usage:
-// color.Green.Print("message")
+//
+// color.Green.Print("message")
+//
// OR:
-// green := color.FgGreen.Print
-// green("message")
-func (c Color) Print(args ...interface{}) {
+//
+// green := color.FgGreen.Print
+// green("message")
+func (c Color) Print(args ...any) {
doPrintV2(c.Code(), fmt.Sprint(args...))
}
// Printf format and print messages.
//
// Usage:
-// color.Cyan.Printf("string %s", "arg0")
-func (c Color) Printf(format string, a ...interface{}) {
+//
+// color.Cyan.Printf("string %s", "arg0")
+func (c Color) Printf(format string, a ...any) {
doPrintV2(c.Code(), fmt.Sprintf(format, a...))
}
// Println messages with new line
-func (c Color) Println(a ...interface{}) { doPrintlnV2(c.String(), a) }
+func (c Color) Println(a ...any) { doPrintlnV2(c.String(), a) }
// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
//
// Usage:
-// lightCyan := Cyan.Light()
-// lightCyan.Print("message")
+//
+// lightCyan := Cyan.Light()
+// lightCyan.Print("message")
func (c Color) Light() Color {
- val := int(c)
+ val := uint8(c)
if val >= 30 && val <= 47 {
- return Color(uint8(c) + 60)
+ return Color(val + 60)
}
// don't change
@@ -252,12 +272,13 @@ func (c Color) Light() Color {
// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
//
// Usage:
-// cyan := LightCyan.Darken()
-// cyan.Print("message")
+//
+// cyan := LightCyan.Darken()
+// cyan.Print("message")
func (c Color) Darken() Color {
- val := int(c)
+ val := uint8(c)
if val >= 90 && val <= 107 {
- return Color(uint8(c) - 60)
+ return Color(val - 60)
}
// don't change
@@ -315,7 +336,7 @@ func (c Color) RGB() RGBColor {
return emptyRGBColor
}
- return HEX(Basic2hex(val))
+ return HEX(Basic2hex(val), c.IsBg())
}
// Code convert to code string. eg "35"
@@ -328,8 +349,23 @@ func (c Color) String() string {
return strconv.FormatInt(int64(c), 10)
}
+// IsBg check is background color
+func (c Color) IsBg() bool {
+ val := uint8(c)
+ return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax
+}
+
+// IsFg check is foreground color
+func (c Color) IsFg() bool {
+ val := uint8(c)
+ return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax
+}
+
+// IsOption check is option code: 0-9
+func (c Color) IsOption() bool { return uint8(c) < OptMax }
+
// IsValid color value
-func (c Color) IsValid() bool { return c < 107 }
+func (c Color) IsValid() bool { return uint8(c) < HiBgMax }
/*************************************************************
* basic color maps
@@ -461,9 +497,7 @@ func Fg2Bg(val uint8) uint8 {
}
// Basic2nameMap data
-func Basic2nameMap() map[uint8]string {
- return basic2nameMap
-}
+func Basic2nameMap() map[uint8]string { return basic2nameMap }
// func initName2basicMap() map[string]uint8 {
// n2b := make(map[string]uint8, len(basic2nameMap))
diff --git a/vendor/github.com/gookit/color/color_256.go b/vendor/github.com/gookit/color/color_256.go
index c95c0f7b..79ae5f8d 100644
--- a/vendor/github.com/gookit/color/color_256.go
+++ b/vendor/github.com/gookit/color/color_256.go
@@ -19,16 +19,19 @@ from wikipedia, 256 color:
// tpl for 8 bit 256 color(`2^8`)
//
// format:
-// ESC[ … 38;5; … m // 选择前景色
-// ESC[ … 48;5; … m // 选择背景色
+//
+// ESC[ … 38;5; … m // 选择前景色
+// ESC[ … 48;5; … m // 选择背景色
//
// example:
-// fg "\x1b[38;5;242m"
-// bg "\x1b[48;5;208m"
-// both "\x1b[38;5;242;48;5;208m"
+//
+// 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位
+//
+// 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"
@@ -40,19 +43,21 @@ const (
* 8bit(256) Color: Bit8Color Color256
*************************************************************/
-// Color256 256 color (8 bit), uint8 range at 0 - 255
+// 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
+//
+// 0: color value
+// 1: color type; Fg=0, Bg=1, >1: unset value
//
// example:
-// fg color: [152, 0]
-// bg color: [152, 1]
//
-// NOTICE: now support 256 color on windows CMD, PowerShell
+// fg color: [152, 0]
+// bg color: [152, 1]
+//
// lint warn - Name starts with package name
type Color256 [2]uint8
type Bit8Color = Color256 // alias
@@ -87,27 +92,27 @@ func (c Color256) Reset() error {
}
// Print print message
-func (c Color256) Print(a ...interface{}) {
+func (c Color256) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
-func (c Color256) Printf(format string, a ...interface{}) {
+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 ...interface{}) {
+func (c Color256) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
-func (c Color256) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+func (c Color256) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
@@ -159,9 +164,7 @@ func (c Color256) String() string {
}
// IsFg color
-func (c Color256) IsFg() bool {
- return c[1] == AsFg
-}
+func (c Color256) IsFg() bool { return c[1] == AsFg }
// ToFg 256 color
func (c Color256) ToFg() Color256 {
@@ -170,9 +173,7 @@ func (c Color256) ToFg() Color256 {
}
// IsBg color
-func (c Color256) IsBg() bool {
- return c[1] == AsBg
-}
+func (c Color256) IsBg() bool { return c[1] == AsBg }
// ToBg 256 color
func (c Color256) ToBg() Color256 {
@@ -181,9 +182,7 @@ func (c Color256) ToBg() Color256 {
}
// IsEmpty value
-func (c Color256) IsEmpty() bool {
- return c[1] > 1
-}
+func (c Color256) IsEmpty() bool { return c[1] > 1 }
/*************************************************************
* 8bit(256) Style
@@ -206,9 +205,10 @@ type Style256 struct {
// S256 create a color256 style
//
// Usage:
-// s := color.S256()
-// s := color.S256(132) // fg
-// s := color.S256(132, 203) // fg and bg
+//
+// 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)
@@ -256,27 +256,27 @@ func (s *Style256) AddOpts(opts ...Color) *Style256 {
}
// Print message
-func (s *Style256) Print(a ...interface{}) {
+func (s *Style256) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
-func (s *Style256) Printf(format string, a ...interface{}) {
+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 ...interface{}) {
+func (s *Style256) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
-func (s *Style256) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+func (s *Style256) Sprintf(format string, a ...any) string {
return RenderString(s.Code(), fmt.Sprintf(format, a...))
}
diff --git a/vendor/github.com/gookit/color/color_rgb.go b/vendor/github.com/gookit/color/color_rgb.go
index ff3c1bb0..bc129b71 100644
--- a/vendor/github.com/gookit/color/color_rgb.go
+++ b/vendor/github.com/gookit/color/color_rgb.go
@@ -8,20 +8,24 @@ import (
// 24 bit RGB color
// RGB:
-// R 0-255 G 0-255 B 0-255
-// R 00-FF G 00-FF B 00-FF (16进制)
+//
+// R 0-255 G 0-255 B 0-255
+// R 00-FF G 00-FF B 00-FF (16进制)
//
// Format:
-// ESC[ … 38;2;;; … m // Select RGB foreground color
-// ESC[ … 48;2;;; … m // Choose RGB background color
+//
+// ESC[ … 38;2;;; … m // Select RGB foreground color
+// ESC[ … 48;2;;; … 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位
+//
+// 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
+//
+// 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"
@@ -40,17 +44,17 @@ const (
*************************************************************/
// 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}
//
-// NOTICE: now support RGB color on Windows CMD, PowerShell
+// // 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
@@ -59,9 +63,10 @@ var emptyRGBColor = RGBColor{3: 99}
// RGB color create.
//
// Usage:
-// c := RGB(30,144,255)
-// c := RGB(30,144,255, true)
-// c.Print("message")
+//
+// 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] {
@@ -90,11 +95,12 @@ func RgbFromInts(rgb []int, isBg ...bool) RGBColor {
// 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")
+//
+// 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...)
@@ -139,11 +145,12 @@ func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
// 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")
+// 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 {
@@ -180,27 +187,27 @@ func (c RGBColor) Reset() error {
}
// Print print message
-func (c RGBColor) Print(a ...interface{}) {
+func (c RGBColor) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
-func (c RGBColor) Printf(format string, a ...interface{}) {
+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 ...interface{}) {
+func (c RGBColor) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
-func (c RGBColor) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+func (c RGBColor) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
@@ -243,6 +250,18 @@ func (c RGBColor) String() string {
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
@@ -279,8 +298,8 @@ func (c RGBColor) C16() Color { return c.Basic() }
// 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
+// 1 Has been set
+// ^1 Not set
type RGBStyle struct {
// Name of the style
Name string
@@ -303,8 +322,9 @@ func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle {
// HEXStyle create a RGBStyle from HEX color string.
//
// Usage:
-// s := HEXStyle("aabbcc", "eee")
-// s.Print("message")
+//
+// s := HEXStyle("aabbcc", "eee")
+// s.Print("message")
func HEXStyle(fg string, bg ...string) *RGBStyle {
s := &RGBStyle{}
if len(bg) > 0 {
@@ -320,8 +340,9 @@ func HEXStyle(fg string, bg ...string) *RGBStyle {
// RGBStyleFromString create a RGBStyle from color value string.
//
// Usage:
-// s := RGBStyleFromString("170,187,204", "70,87,4")
-// s.Print("message")
+//
+// s := RGBStyleFromString("170,187,204", "70,87,4")
+// s.Print("message")
func RGBStyleFromString(fg string, bg ...string) *RGBStyle {
s := &RGBStyle{}
if len(bg) > 0 {
@@ -363,27 +384,27 @@ func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle {
}
// Print print message
-func (s *RGBStyle) Print(a ...interface{}) {
+func (s *RGBStyle) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
-func (s *RGBStyle) Printf(format string, a ...interface{}) {
+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 ...interface{}) {
+func (s *RGBStyle) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
-func (s *RGBStyle) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+func (s *RGBStyle) Sprintf(format string, a ...any) string {
return RenderString(s.String(), fmt.Sprintf(format, a...))
}
diff --git a/vendor/github.com/gookit/color/color_tag.go b/vendor/github.com/gookit/color/color_tag.go
index 4f6fed93..1d2b9d3f 100644
--- a/vendor/github.com/gookit/color/color_tag.go
+++ b/vendor/github.com/gookit/color/color_tag.go
@@ -41,7 +41,8 @@ var (
// There are internal defined fg color tags
//
// Usage:
-// content text>
+//
+// content text>
//
// @notice 加 0 在前面是为了防止之前的影响到现在的设置
var colorTags = map[string]string{
@@ -324,15 +325,17 @@ func (tp *TagParser) ParseByEnv(str string) string {
return tp.Parse(str)
}
-// Parse parse given string, replace color tag and return rendered string
+// Parse given string, replace color tag and return rendered string
//
// Use built in tags:
-// CONTENT>
-// // e.g: `message>`
+//
+// CONTENT>
+// // e.g: `message>`
//
// Custom tag attributes:
-// `CONTENT>`
-// // e.g: `wel>`
+//
+// `CONTENT>`
+// // e.g: `wel>`
func (tp *TagParser) Parse(str string) string {
// not contains color tag
if !strings.Contains(str, ">") {
@@ -376,26 +379,30 @@ func ReplaceTag(str string) string {
// ParseCodeFromAttr parse color attributes.
//
// attr format:
-// // VALUE please see var: FgColors, BgColors, AllOptions
-// "fg=VALUE;bg=VALUE;op=VALUE"
+//
+// // 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"
+//
+// "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
+//
+// // hex
// "fg=fc1cac"
// "fg=fc1cac;bg=c2c3c4"
-// // r,g,b
+// // r,g,b
// "fg=23,45,214"
// "fg=23,45,214;bg=109,99,88"
func ParseCodeFromAttr(attr string) (code string) {
@@ -476,12 +483,10 @@ func ClearTag(s string) string {
*************************************************************/
// GetTagCode get color code by tag name
-func GetTagCode(name string) string {
- return colorTags[name]
-}
+func GetTagCode(name string) string { return colorTags[name] }
// ApplyTag for messages
-func ApplyTag(tag string, a ...interface{}) string {
+func ApplyTag(tag string, a ...any) string {
return RenderCode(GetTagCode(tag), a...)
}
@@ -510,11 +515,12 @@ func IsDefinedTag(name string) bool {
// Tag value is a defined style name
// Usage:
-// Tag("info").Println("message")
+//
+// Tag("info").Println("message")
type Tag string
// Print messages
-func (tg Tag) Print(a ...interface{}) {
+func (tg Tag) Print(a ...any) {
name := string(tg)
str := fmt.Sprint(a...)
@@ -526,7 +532,7 @@ func (tg Tag) Print(a ...interface{}) {
}
// Printf format and print messages
-func (tg Tag) Printf(format string, a ...interface{}) {
+func (tg Tag) Printf(format string, a ...any) {
name := string(tg)
str := fmt.Sprintf(format, a...)
@@ -538,7 +544,7 @@ func (tg Tag) Printf(format string, a ...interface{}) {
}
// Println messages line
-func (tg Tag) Println(a ...interface{}) {
+func (tg Tag) Println(a ...any) {
name := string(tg)
if stl := GetStyle(name); !stl.IsEmpty() {
stl.Println(a...)
@@ -548,12 +554,12 @@ func (tg Tag) Println(a ...interface{}) {
}
// Sprint render messages
-func (tg Tag) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+func (tg Tag) Sprintf(format string, a ...any) string {
tag := string(tg)
str := fmt.Sprintf(format, a...)
diff --git a/vendor/github.com/gookit/color/convert.go b/vendor/github.com/gookit/color/convert.go
index 39aac7d2..c7103536 100644
--- a/vendor/github.com/gookit/color/convert.go
+++ b/vendor/github.com/gookit/color/convert.go
@@ -52,6 +52,7 @@ var (
// ---------- 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
@@ -61,7 +62,7 @@ var (
35: "c839c5", // magenta
36: "20c5c6", // cyan
37: "c7c7c7", // white
- // - don't add bg color
+ // - don't add bg color, convert to fg color for convert to RGB
// 40: "000000", // black
// 41: "c51e14", // red
// 42: "1dc121", // green
@@ -428,10 +429,11 @@ 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]
+//
+// 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 == "" {
@@ -474,6 +476,7 @@ 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))
@@ -488,10 +491,15 @@ func RgbToHex(rgb []int) string {
* 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 {
- val = Fg2Bg(val)
- return basic2hexMap[val]
+ return BasicToHex(val)
}
// Hex2basic convert hex string to basic color code.
@@ -663,6 +671,7 @@ func C256ToRgbV1(val uint8) (rgb []uint8) {
// 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
@@ -677,6 +686,7 @@ func HslIntToRgb(h, s, l int) (rgb []uint8) {
// 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
diff --git a/vendor/github.com/gookit/color/printer.go b/vendor/github.com/gookit/color/printer.go
index 326aabc0..985a0b62 100644
--- a/vendor/github.com/gookit/color/printer.go
+++ b/vendor/github.com/gookit/color/printer.go
@@ -9,18 +9,19 @@ import "fmt"
// PrinterFace interface
type PrinterFace interface {
fmt.Stringer
- Sprint(a ...interface{}) string
- Sprintf(format string, a ...interface{}) string
- Print(a ...interface{})
- Printf(format string, a ...interface{})
- Println(a ...interface{})
+ 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")
+//
+// p := &Printer{Code: "32;45;3"}
+// p.Print("message")
type Printer struct {
// NoColor disable color.
NoColor bool
@@ -40,27 +41,27 @@ func (p *Printer) String() string {
}
// Sprint returns rendering colored messages
-func (p *Printer) Sprint(a ...interface{}) string {
+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 ...interface{}) string {
+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 ...interface{}) {
+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 ...interface{}) {
+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 ...interface{}) {
+func (p *Printer) Println(a ...any) {
doPrintlnV2(p.Code, a)
}
@@ -77,46 +78,56 @@ func (p *Printer) IsEmpty() bool {
type SimplePrinter struct{}
// Print message
-func (s *SimplePrinter) Print(v ...interface{}) {
+func (s *SimplePrinter) Print(v ...any) {
Print(v...)
}
// Printf message
-func (s *SimplePrinter) Printf(format string, v ...interface{}) {
+func (s *SimplePrinter) Printf(format string, v ...any) {
Printf(format, v...)
}
// Println message
-func (s *SimplePrinter) Println(v ...interface{}) {
+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 ...interface{}) {
+func (s *SimplePrinter) Infof(format string, a ...any) {
Info.Printf(format, a...)
}
// Infoln message
-func (s *SimplePrinter) Infoln(a ...interface{}) {
+func (s *SimplePrinter) Infoln(a ...any) {
Info.Println(a...)
}
// Warnf message
-func (s *SimplePrinter) Warnf(format string, a ...interface{}) {
+func (s *SimplePrinter) Warnf(format string, a ...any) {
Warn.Printf(format, a...)
}
// Warnln message
-func (s *SimplePrinter) Warnln(a ...interface{}) {
+func (s *SimplePrinter) Warnln(a ...any) {
Warn.Println(a...)
}
// Errorf message
-func (s *SimplePrinter) Errorf(format string, a ...interface{}) {
+func (s *SimplePrinter) Errorf(format string, a ...any) {
Error.Printf(format, a...)
}
// Errorln message
-func (s *SimplePrinter) Errorln(a ...interface{}) {
+func (s *SimplePrinter) Errorln(a ...any) {
Error.Println(a...)
}
diff --git a/vendor/github.com/gookit/color/quickstart.go b/vendor/github.com/gookit/color/quickstart.go
index 4dbd1a43..b368b8a1 100644
--- a/vendor/github.com/gookit/color/quickstart.go
+++ b/vendor/github.com/gookit/color/quickstart.go
@@ -5,104 +5,104 @@ package color
*************************************************************/
// Redp print message with Red color
-func Redp(a ...interface{}) { Red.Print(a...) }
+func Redp(a ...any) { Red.Print(a...) }
// Redf print message with Red color
-func Redf(format string, a ...interface{}) { Red.Printf(format, a...) }
+func Redf(format string, a ...any) { Red.Printf(format, a...) }
// Redln print message line with Red color
-func Redln(a ...interface{}) { Red.Println(a...) }
+func Redln(a ...any) { Red.Println(a...) }
// Bluep print message with Blue color
-func Bluep(a ...interface{}) { Blue.Print(a...) }
+func Bluep(a ...any) { Blue.Print(a...) }
// Bluef print message with Blue color
-func Bluef(format string, a ...interface{}) { Blue.Printf(format, a...) }
+func Bluef(format string, a ...any) { Blue.Printf(format, a...) }
// Blueln print message line with Blue color
-func Blueln(a ...interface{}) { Blue.Println(a...) }
+func Blueln(a ...any) { Blue.Println(a...) }
// Cyanp print message with Cyan color
-func Cyanp(a ...interface{}) { Cyan.Print(a...) }
+func Cyanp(a ...any) { Cyan.Print(a...) }
// Cyanf print message with Cyan color
-func Cyanf(format string, a ...interface{}) { Cyan.Printf(format, a...) }
+func Cyanf(format string, a ...any) { Cyan.Printf(format, a...) }
// Cyanln print message line with Cyan color
-func Cyanln(a ...interface{}) { Cyan.Println(a...) }
+func Cyanln(a ...any) { Cyan.Println(a...) }
// Grayp print message with Gray color
-func Grayp(a ...interface{}) { Gray.Print(a...) }
+func Grayp(a ...any) { Gray.Print(a...) }
// Grayf print message with Gray color
-func Grayf(format string, a ...interface{}) { Gray.Printf(format, a...) }
+func Grayf(format string, a ...any) { Gray.Printf(format, a...) }
// Grayln print message line with Gray color
-func Grayln(a ...interface{}) { Gray.Println(a...) }
+func Grayln(a ...any) { Gray.Println(a...) }
// Greenp print message with Green color
-func Greenp(a ...interface{}) { Green.Print(a...) }
+func Greenp(a ...any) { Green.Print(a...) }
// Greenf print message with Green color
-func Greenf(format string, a ...interface{}) { Green.Printf(format, a...) }
+func Greenf(format string, a ...any) { Green.Printf(format, a...) }
// Greenln print message line with Green color
-func Greenln(a ...interface{}) { Green.Println(a...) }
+func Greenln(a ...any) { Green.Println(a...) }
// Yellowp print message with Yellow color
-func Yellowp(a ...interface{}) { Yellow.Print(a...) }
+func Yellowp(a ...any) { Yellow.Print(a...) }
// Yellowf print message with Yellow color
-func Yellowf(format string, a ...interface{}) { Yellow.Printf(format, a...) }
+func Yellowf(format string, a ...any) { Yellow.Printf(format, a...) }
// Yellowln print message line with Yellow color
-func Yellowln(a ...interface{}) { Yellow.Println(a...) }
+func Yellowln(a ...any) { Yellow.Println(a...) }
// Magentap print message with Magenta color
-func Magentap(a ...interface{}) { Magenta.Print(a...) }
+func Magentap(a ...any) { Magenta.Print(a...) }
// Magentaf print message with Magenta color
-func Magentaf(format string, a ...interface{}) { Magenta.Printf(format, a...) }
+func Magentaf(format string, a ...any) { Magenta.Printf(format, a...) }
// Magentaln print message line with Magenta color
-func Magentaln(a ...interface{}) { Magenta.Println(a...) }
+func Magentaln(a ...any) { Magenta.Println(a...) }
/*************************************************************
* quick use style print message
*************************************************************/
// Infop print message with Info color
-func Infop(a ...interface{}) { Info.Print(a...) }
+func Infop(a ...any) { Info.Print(a...) }
// Infof print message with Info style
-func Infof(format string, a ...interface{}) { Info.Printf(format, a...) }
+func Infof(format string, a ...any) { Info.Printf(format, a...) }
// Infoln print message with Info style
-func Infoln(a ...interface{}) { Info.Println(a...) }
+func Infoln(a ...any) { Info.Println(a...) }
// Successp print message with success color
-func Successp(a ...interface{}) { Success.Print(a...) }
+func Successp(a ...any) { Success.Print(a...) }
// Successf print message with success style
-func Successf(format string, a ...interface{}) { Success.Printf(format, a...) }
+func Successf(format string, a ...any) { Success.Printf(format, a...) }
// Successln print message with success style
-func Successln(a ...interface{}) { Success.Println(a...) }
+func Successln(a ...any) { Success.Println(a...) }
// Errorp print message with Error color
-func Errorp(a ...interface{}) { Error.Print(a...) }
+func Errorp(a ...any) { Error.Print(a...) }
// Errorf print message with Error style
-func Errorf(format string, a ...interface{}) { Error.Printf(format, a...) }
+func Errorf(format string, a ...any) { Error.Printf(format, a...) }
// Errorln print message with Error style
-func Errorln(a ...interface{}) { Error.Println(a...) }
+func Errorln(a ...any) { Error.Println(a...) }
// Warnp print message with Warn color
-func Warnp(a ...interface{}) { Warn.Print(a...) }
+func Warnp(a ...any) { Warn.Print(a...) }
// Warnf print message with Warn style
-func Warnf(format string, a ...interface{}) { Warn.Printf(format, a...) }
+func Warnf(format string, a ...any) { Warn.Printf(format, a...) }
// Warnln print message with Warn style
-func Warnln(a ...interface{}) { Warn.Println(a...) }
+func Warnln(a ...any) { Warn.Println(a...) }
diff --git a/vendor/github.com/gookit/color/style.go b/vendor/github.com/gookit/color/style.go
index fad76fb3..353d39f1 100644
--- a/vendor/github.com/gookit/color/style.go
+++ b/vendor/github.com/gookit/color/style.go
@@ -12,12 +12,14 @@ import (
// Style a 16 color style. can add: fg color, bg color, color options
//
// Example:
-// color.Style{color.FgGreen}.Print("message")
+//
+// 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")
@@ -35,45 +37,49 @@ func (s *Style) Add(cs ...Color) {
*s = append(*s, cs...)
}
-// Render render text
+// 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 ...interface{}) string {
+//
+// 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 line.
+// 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 ...interface{}) string {
+//
+// 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 ...interface{}) string {
+func (s Style) Sprint(a ...any) string {
return RenderCode(s.String(), a...)
}
// Sprintf format and render message.
-func (s Style) Sprintf(format string, a ...interface{}) string {
+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 ...interface{}) {
+func (s Style) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf render and print text
-func (s Style) Printf(format string, a ...interface{}) {
+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 ...interface{}) {
+func (s Style) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
@@ -115,20 +121,20 @@ func (t *Theme) Save() {
}
// Tips use name as title, only apply style for name
-func (t *Theme) Tips(format string, a ...interface{}) {
+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 ...interface{}) {
+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 ...interface{}) {
+func (t *Theme) Block(format string, a ...any) {
title := strings.ToUpper(t.Name) + ":\n"
t.Println(title, fmt.Sprintf(format, a...))
@@ -140,10 +146,11 @@ func (t *Theme) Block(format string, a ...interface{}) {
// 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")
+//
+// 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}}
@@ -175,7 +182,8 @@ var (
// Themes internal defined themes.
// Usage:
-// color.Themes["info"].Println("message")
+//
+// color.Themes["info"].Println("message")
var Themes = map[string]*Theme{
"info": Info,
"note": Note,
@@ -211,7 +219,8 @@ func GetTheme(name string) *Theme {
// Styles internal defined styles, like bootstrap styles.
// Usage:
-// color.Styles["info"].Println("message")
+//
+// color.Styles["info"].Println("message")
var Styles = map[string]Style{
"info": {OpReset, FgGreen},
"note": {OpBold, FgLightCyan},
@@ -285,31 +294,31 @@ func (s *Scheme) Style(name string) Style {
}
// Infof message print
-func (s *Scheme) Infof(format string, a ...interface{}) {
+func (s *Scheme) Infof(format string, a ...any) {
s.Styles["info"].Printf(format, a...)
}
// Infoln message print
-func (s *Scheme) Infoln(v ...interface{}) {
+func (s *Scheme) Infoln(v ...any) {
s.Styles["info"].Println(v...)
}
// Warnf message print
-func (s *Scheme) Warnf(format string, a ...interface{}) {
+func (s *Scheme) Warnf(format string, a ...any) {
s.Styles["warn"].Printf(format, a...)
}
// Warnln message print
-func (s *Scheme) Warnln(v ...interface{}) {
+func (s *Scheme) Warnln(v ...any) {
s.Styles["warn"].Println(v...)
}
// Errorf message print
-func (s *Scheme) Errorf(format string, a ...interface{}) {
+func (s *Scheme) Errorf(format string, a ...any) {
s.Styles["error"].Printf(format, a...)
}
// Errorln message print
-func (s *Scheme) Errorln(v ...interface{}) {
+func (s *Scheme) Errorln(v ...any) {
s.Styles["error"].Println(v...)
}
diff --git a/vendor/github.com/gookit/color/utils.go b/vendor/github.com/gookit/color/utils.go
index 4554b27e..b6920f6d 100644
--- a/vendor/github.com/gookit/color/utils.go
+++ b/vendor/github.com/gookit/color/utils.go
@@ -32,39 +32,31 @@ func ResetTerminal() error {
*************************************************************/
// Print render color tag and print messages
-func Print(a ...interface{}) {
+func Print(a ...any) {
Fprint(output, a...)
}
// Printf format and print messages
-func Printf(format string, a ...interface{}) {
+func Printf(format string, a ...any) {
Fprintf(output, format, a...)
}
// Println messages with new line
-func Println(a ...interface{}) {
+func Println(a ...any) {
Fprintln(output, a...)
}
// Fprint print rendered messages to writer
//
// Notice: will ignore print error
-func Fprint(w io.Writer, a ...interface{}) {
+func Fprint(w io.Writer, a ...any) {
_, err := fmt.Fprint(w, Render(a...))
saveInternalError(err)
-
- // if isLikeInCmd {
- // renderColorCodeOnCmd(func() {
- // _, _ = fmt.Fprint(w, Render(a...))
- // })
- // } else {
- // _, _ = fmt.Fprint(w, Render(a...))
- // }
}
// Fprintf print format and rendered messages to writer.
// Notice: will ignore print error
-func Fprintf(w io.Writer, format string, a ...interface{}) {
+func Fprintf(w io.Writer, format string, a ...any) {
str := fmt.Sprintf(format, a...)
_, err := fmt.Fprint(w, ReplaceTag(str))
saveInternalError(err)
@@ -72,7 +64,7 @@ func Fprintf(w io.Writer, format string, a ...interface{}) {
// Fprintln print rendered messages line to writer
// Notice: will ignore print error
-func Fprintln(w io.Writer, a ...interface{}) {
+func Fprintln(w io.Writer, a ...any) {
str := formatArgsForPrintln(a)
_, err := fmt.Fprintln(w, ReplaceTag(str))
saveInternalError(err)
@@ -80,7 +72,7 @@ func Fprintln(w io.Writer, a ...interface{}) {
// Lprint passes colored messages to a log.Logger for printing.
// Notice: should be goroutine safe
-func Lprint(l *log.Logger, a ...interface{}) {
+func Lprint(l *log.Logger, a ...any) {
l.Print(Render(a...))
}
@@ -90,7 +82,7 @@ func Lprint(l *log.Logger, a ...interface{}) {
//
// text := Render("hello> world>!")
// fmt.Println(text)
-func Render(a ...interface{}) string {
+func Render(a ...any) string {
if len(a) == 0 {
return ""
}
@@ -98,28 +90,23 @@ func Render(a ...interface{}) string {
}
// Sprint parse color tags, return rendered string
-func Sprint(a ...interface{}) 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 ...interface{}) 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)
-}
+func String(s string) string { return ReplaceTag(s) }
// Text alias of the ReplaceTag
-func Text(s string) string {
- return ReplaceTag(s)
-}
+func Text(s string) string { return ReplaceTag(s) }
// Uint8sToInts convert []uint8 to []int
// func Uint8sToInts(u8s []uint8 ) []int {
@@ -138,25 +125,17 @@ func Text(s string) string {
func doPrintV2(code, str string) {
_, err := fmt.Fprint(output, RenderString(code, str))
saveInternalError(err)
-
- // if isLikeInCmd {
- // renderColorCodeOnCmd(func() {
- // _, _ = fmt.Fprint(output, RenderString(code, str))
- // })
- // } else {
- // _, _ = fmt.Fprint(output, RenderString(code, str))
- // }
}
// new implementation, support render full color code on pwsh.exe, cmd.exe
-func doPrintlnV2(code string, args []interface{}) {
+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 []interface{}) (message string) {
+func formatArgsForPrintln(args []any) (message string) {
if ln := len(args); ln == 0 {
message = ""
} else if ln == 1 {
@@ -178,7 +157,7 @@ func formatArgsForPrintln(args []interface{}) (message string) {
// return debugMode == "on"
// }
-func debugf(f string, v ...interface{}) {
+func debugf(f string, v ...any) {
if debugMode {
fmt.Print("COLOR_DEBUG: ")
fmt.Printf(f, v...)
diff --git a/vendor/github.com/itchyny/gojq/CHANGELOG.md b/vendor/github.com/itchyny/gojq/CHANGELOG.md
index cee2ce33..65e605fb 100644
--- a/vendor/github.com/itchyny/gojq/CHANGELOG.md
+++ b/vendor/github.com/itchyny/gojq/CHANGELOG.md
@@ -1,4 +1,51 @@
# Changelog
+## [v0.12.12](https://github.com/itchyny/gojq/compare/v0.12.11..v0.12.12) (2023-03-01)
+* fix assignment operator (`=`) with overlapping paths and multiple values (`[[]] | .. = ..`)
+* fix crash on multiplying large numbers to an empty string (`9223372036854775807 * ""`)
+* improve zsh completion file
+
+## [v0.12.11](https://github.com/itchyny/gojq/compare/v0.12.10..v0.12.11) (2022-12-24)
+* fix crash on assignment operator (`=`) with multiple values (`. = (0,0)`)
+* fix `isnormal` and `normals` functions against subnormal numbers
+
+## [v0.12.10](https://github.com/itchyny/gojq/compare/v0.12.9..v0.12.10) (2022-12-01)
+* fix `break` in `try`-`catch` query (`label $x | try break $x catch .`)
+* fix path value validation for `getpath` function (`path(getpath([[0]][0]))`)
+* fix path value validation for custom iterator functions
+* fix `walk` function with argument emitting multiple values (`[1],{x:1} | walk(.,0)`)
+* fix `@csv`, `@tsv`, `@sh` to escape the null character (`["\u0000"] | @csv,@tsv,@sh`)
+* improve performance of assignment operator (`=`), update-assignment operator (`|=`),
+ `map_values`, `del`, `delpaths`, `walk`, `ascii_downcase`, and `ascii_upcase` functions
+
+## [v0.12.9](https://github.com/itchyny/gojq/compare/v0.12.8..v0.12.9) (2022-09-01)
+* fix `fromjson` to emit error on unexpected trailing string
+* fix path analyzer on variable argument evaluation (`def f($x): .y; path(f(.x))`)
+* fix raw input option `--raw-input` (`-R`) to keep carriage returns and support 64KiB+ lines
+
+## [v0.12.8](https://github.com/itchyny/gojq/compare/v0.12.7..v0.12.8) (2022-06-01)
+* implement `gojq.Compare` for comparing values in custom internal functions
+* implement `gojq.TypeOf` for obtaining type name of values in custom internal functions
+* implement `gojq.Preview` for previewing values for error messages of custom internal functions
+* fix query lexer to parse string literals as JSON to support surrogate pairs (`"\ud83d\ude04"`)
+* fix priority bug of declared and builtin functions (`def empty: .; null | select(.)`)
+* fix string indexing by index out of bounds to emit `null` (`"abc" | .[3]`)
+* fix array binding pattern not to match against strings (`"abc" as [$a] ?// $a | $a`)
+* fix `sub` and `gsub` functions to emit results in the same order of jq
+* fix `fromjson` to keep integer precision (`"10000000000000000" | fromjson + 1`)
+* fix stream option to raise error against incomplete JSON input
+* improve array updating index and string repetition to increase limitations
+* improve `mktime` to support nanoseconds, just like `gmtime` and `now`
+* improve query lexer to report unterminated string literals
+* improve performance of string indexing and slicing by reducing allocations
+* improve performance of object and array indexing, slicing, and iteration,
+ by validating path values by comparing data addresses. This change improves jq
+ compatibility of path value validation (`{} | {}.x = 0`, `[0] | [.[]][] = 1`).
+ Also optimize constant indexing and slicing by specialized instruction
+* improve performance of `add` (on array of strings), `flatten`, `min`, `max`,
+ `sort`, `unique`, `join`, `to_entries`, `from_entries`, `indices`, `index`,
+ `rindex`, `startswith`, `endswith`, `ltrimstr`, `rtrimstr`, `explode`,
+ `capture`, `sub`, and `gsub` functions
+
## [v0.12.7](https://github.com/itchyny/gojq/compare/v0.12.6..v0.12.7) (2022-03-01)
* fix precedence of try expression against operators (`try 0 * error(0)`)
* fix iterator suffix with optional operator (`0 | .x[]?`)
@@ -187,7 +234,7 @@
## [v0.7.0](https://github.com/itchyny/gojq/compare/v0.6.0..v0.7.0) (2019-12-22)
* implement YAML input (`--yaml-input`) and output (`--yaml-output`)
* fix pipe in object value
-* fix precedence of if, try, reduce and foreach expressions
+* fix precedence of `if`, `try`, `reduce` and `foreach` expressions
* release from GitHub Actions
## [v0.6.0](https://github.com/itchyny/gojq/compare/v0.5.0..v0.6.0) (2019-08-26)
diff --git a/vendor/github.com/itchyny/gojq/Dockerfile b/vendor/github.com/itchyny/gojq/Dockerfile
index 7beaf4ed..284ece77 100644
--- a/vendor/github.com/itchyny/gojq/Dockerfile
+++ b/vendor/github.com/itchyny/gojq/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.17 AS builder
+FROM golang:1.19 AS builder
WORKDIR /app
COPY . .
diff --git a/vendor/github.com/itchyny/gojq/LICENSE b/vendor/github.com/itchyny/gojq/LICENSE
index e3fc027c..3f4fcb26 100644
--- a/vendor/github.com/itchyny/gojq/LICENSE
+++ b/vendor/github.com/itchyny/gojq/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2019-2022 itchyny
+Copyright (c) 2019-2023 itchyny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/itchyny/gojq/Makefile b/vendor/github.com/itchyny/gojq/Makefile
index b5de9126..b7cdb400 100644
--- a/vendor/github.com/itchyny/gojq/Makefile
+++ b/vendor/github.com/itchyny/gojq/Makefile
@@ -1,8 +1,8 @@
BIN := gojq
VERSION := $$(make -s show-version)
VERSION_PATH := cli
-CURRENT_REVISION := $(shell git rev-parse --short HEAD)
-BUILD_LDFLAGS := "-s -w -X github.com/itchyny/$(BIN)/cli.revision=$(CURRENT_REVISION)"
+CURRENT_REVISION = $(shell git rev-parse --short HEAD)
+BUILD_LDFLAGS = "-s -w -X github.com/itchyny/$(BIN)/cli.revision=$(CURRENT_REVISION)"
GOBIN ?= $(shell go env GOPATH)/bin
SHELL := /bin/bash
@@ -19,7 +19,7 @@ build-dev: parser.go builtin.go
.PHONY: build-debug
build-debug: parser.go builtin.go
- go build -tags debug -ldflags=$(BUILD_LDFLAGS) -o $(BIN) ./cmd/$(BIN)
+ go build -tags gojq_debug -ldflags=$(BUILD_LDFLAGS) -o $(BIN) ./cmd/$(BIN)
builtin.go: builtin.jq parser.go.y parser.go query.go operator.go _tools/*
GOOS= GOARCH= go generate
@@ -33,26 +33,26 @@ $(GOBIN)/goyacc:
.PHONY: install
install:
- go install -ldflags=$(BUILD_LDFLAGS) ./...
+ go install -ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)
.PHONY: install-dev
install-dev: parser.go builtin.go
- go install -ldflags=$(BUILD_LDFLAGS) ./...
+ go install -ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)
.PHONY: install-debug
install-debug: parser.go builtin.go
- go install -tags debug -ldflags=$(BUILD_LDFLAGS) ./...
+ go install -tags gojq_debug -ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)
.PHONY: show-version
show-version: $(GOBIN)/gobump
- @gobump show -r $(VERSION_PATH)
+ @gobump show -r "$(VERSION_PATH)"
$(GOBIN)/gobump:
@go install github.com/x-motemen/gobump/cmd/gobump@latest
.PHONY: cross
cross: $(GOBIN)/goxz CREDITS
- goxz -n $(BIN) -pv=v$(VERSION) -include _$(BIN) -arch=amd64,arm64 \
+ goxz -n $(BIN) -pv=v$(VERSION) -include _$(BIN) \
-build-ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)
$(GOBIN)/goxz:
@@ -72,7 +72,7 @@ test: build
.PHONY: lint
lint: $(GOBIN)/staticcheck
go vet ./...
- staticcheck -checks all,-ST1000 -tags debug ./...
+ staticcheck -checks all -tags gojq_debug ./...
$(GOBIN)/staticcheck:
go install honnef.co/go/tools/cmd/staticcheck@latest
@@ -89,27 +89,15 @@ clean:
.PHONY: update
update: export GOPROXY=direct
update:
- rm -f go.sum && go get -u -d ./... && go get -d github.com/mattn/go-runewidth@v0.0.9 && go mod tidy
- sed -i.bak '/require (/,/)/d' go.dev.mod && rm -f go.dev.{sum,mod.bak}
+ go get -u -d ./... && go mod tidy
+ go mod edit -modfile=go.dev.mod -droprequire=github.com/itchyny/{astgen,timefmt}-go
go get -u -d -modfile=go.dev.mod github.com/itchyny/{astgen,timefmt}-go && go generate
.PHONY: bump
bump: $(GOBIN)/gobump
-ifneq ($(shell git status --porcelain),)
- $(error git workspace is dirty)
-endif
-ifneq ($(shell git rev-parse --abbrev-ref HEAD),main)
- $(error current branch is not main)
-endif
+ test -z "$$(git status --porcelain || echo .)"
+ test "$$(git branch --show-current)" = "main"
@gobump up -w "$(VERSION_PATH)"
git commit -am "bump up version to $(VERSION)"
git tag "v$(VERSION)"
- git push origin main
- git push origin "refs/tags/v$(VERSION)"
-
-.PHONY: upload
-upload: $(GOBIN)/ghr
- ghr "v$(VERSION)" goxz
-
-$(GOBIN)/ghr:
- go install github.com/tcnksm/ghr@latest
+ git push --atomic origin main tag "v$(VERSION)"
diff --git a/vendor/github.com/itchyny/gojq/README.md b/vendor/github.com/itchyny/gojq/README.md
index baba061f..6370e440 100644
--- a/vendor/github.com/itchyny/gojq/README.md
+++ b/vendor/github.com/itchyny/gojq/README.md
@@ -75,11 +75,11 @@ docker run -i --rm ghcr.io/itchyny/gojq
## Difference to jq
- gojq is purely implemented with Go language and is completely portable. jq depends on the C standard library so the availability of math functions depends on the library. jq also depends on the regular expression library and it makes build scripts complex.
- gojq implements nice error messages for invalid query and JSON input. The error message of jq is sometimes difficult to tell where to fix the query.
-- gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have `keys_unsorted` function and `--sort-keys` (`-S`) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated. Also, gojq assumes only valid JSON input while jq deals with some JSON extensions; `NaN`, `Infinity` and `[000]`.
-- gojq supports arbitrary-precision integer calculation while jq does not. This is important to keep the precision of numeric IDs or nanosecond values. You can also use gojq to solve some mathematical problems which require big integers. Note that mathematical functions convert integers to floating-point numbers; only addition, subtraction, multiplication, modulo operation, and division (when divisible) keep integer precisions. When you want to calculate floor division of big integers, use `def intdiv($x; $y): ($x - $x % $y) / $y;`, instead of `$x / $y`.
-- gojq fixes various bugs of jq. gojq correctly deletes elements of arrays by `|= empty` ([jq#2051](https://github.com/stedolan/jq/issues/2051)). gojq fixes `try`/`catch` handling ([jq#1859](https://github.com/stedolan/jq/issues/1859), [jq#1885](https://github.com/stedolan/jq/issues/1885), [jq#2140](https://github.com/stedolan/jq/issues/2140)). gojq fixes `nth/2` to output nothing when the count is equal to or larger than the stream size ([jq#1867](https://github.com/stedolan/jq/issues/1867)). gojq consistently counts by characters (not by bytes) in `index`, `rindex`, and `indices` functions; `"12345" | .[index("3"):]` results in `"345"` ([jq#1430](https://github.com/stedolan/jq/issues/1430), [jq#1624](https://github.com/stedolan/jq/issues/1624)), and supports string indexing; `"abcde"[2]` ([jq#1520](https://github.com/stedolan/jq/issues/1520)). gojq accepts indexing query `.e0` ([jq#1526](https://github.com/stedolan/jq/issues/1526), [jq#1651](https://github.com/stedolan/jq/issues/1651)), and allows `gsub` to handle patterns including `"^"` ([jq#2148](https://github.com/stedolan/jq/issues/2148)). gojq improves variable lexer to allow using keywords for variable names, especially in binding patterns, also disallows spaces after `$` ([jq#526](https://github.com/stedolan/jq/issues/526)). gojq fixes handling files with no newline characters at the end ([jq#2374](https://github.com/stedolan/jq/issues/2374)).
-- gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/stedolan/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/stedolan/jq/issues/1931)). gojq improves time formatting and parsing, deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/stedolan/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/stedolan/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/stedolan/jq/issues/929), [jq#2195](https://github.com/stedolan/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/stedolan/jq/issues/1912)).
-- gojq does not support some functions intentionally; `get_jq_origin`, `get_prog_origin`, `get_search_list` (unstable, not listed in jq document), `input_line_number`, `$__loc__` (performance issue), `recurse_down` (deprecated in jq). gojq does not support some flags; `--ascii-output, -a` (performance issue), `--seq` (not used commonly), `--sort-keys, -S` (sorts by default because `map[string]interface{}` does not keep the order), `--unbuffered` (unbuffered by default). gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support some regular expression flags (regular expression engine differences). gojq does not support BOM (`encoding/json` does not support this). gojq disallows using keywords for function names (declaration of `def true: .;` is a confusing query).
+- gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have `keys_unsorted` function and `--sort-keys` (`-S`) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated.
+- gojq supports arbitrary-precision integer calculation while jq does not; jq loses the precision of large integers when calculation is involved. Note that even with gojq, all mathematical functions, including `floor` and `round`, convert integers to floating-point numbers; only addition, subtraction, multiplication, modulo, and division operators (when divisible) keep the integer precision. To calculate floor division of integers without losing the precision, use `def idivide($n): (. - . % $n) / $n;`. To round down floating-point numbers to integers, use `def ifloor: floor | tostring | tonumber;`, but note that this function does not work with large floating-point numbers and also loses the precision of large integers.
+- gojq fixes various bugs of jq. gojq correctly deletes elements of arrays by `|= empty` ([jq#2051](https://github.com/stedolan/jq/issues/2051)). gojq fixes `try`/`catch` handling ([jq#1859](https://github.com/stedolan/jq/issues/1859), [jq#1885](https://github.com/stedolan/jq/issues/1885), [jq#2140](https://github.com/stedolan/jq/issues/2140)). gojq fixes `nth/2` to output nothing when the count is equal to or larger than the stream size ([jq#1867](https://github.com/stedolan/jq/issues/1867)). gojq consistently counts by characters (not by bytes) in `index`, `rindex`, and `indices` functions; `"12345" | .[index("3"):]` results in `"345"` ([jq#1430](https://github.com/stedolan/jq/issues/1430), [jq#1624](https://github.com/stedolan/jq/issues/1624)). gojq handles overlapping occurrence differently in `rindex` and `indices`; `"ababa" | [rindex("aba"), indices("aba")]` results in `[2,[0,2]]` ([jq#2433](https://github.com/stedolan/jq/issues/2433)). gojq supports string indexing; `"abcde"[2]` ([jq#1520](https://github.com/stedolan/jq/issues/1520)). gojq accepts indexing query `.e0` ([jq#1526](https://github.com/stedolan/jq/issues/1526), [jq#1651](https://github.com/stedolan/jq/issues/1651)), and allows `gsub` to handle patterns including `"^"` ([jq#2148](https://github.com/stedolan/jq/issues/2148)). gojq improves variable lexer to allow using keywords for variable names, especially in binding patterns, also disallows spaces after `$` ([jq#526](https://github.com/stedolan/jq/issues/526)). gojq fixes handling files with no newline characters at the end ([jq#2374](https://github.com/stedolan/jq/issues/2374)).
+- gojq truncates down floating-point numbers on indexing (`[0] | .[0.5]` results in `0` not `null`), and slicing (`[0,1,2] | .[0.5:1.5]` results in `[0]` not `[0,1]`). gojq parses unary operators with higher precedence than variable binding (`[-1 as $x | 1,$x]` results in `[1,-1]` not `[-1,-1]`). gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/stedolan/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/stedolan/jq/issues/1931)). gojq improves time formatting and parsing; deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/stedolan/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/stedolan/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/stedolan/jq/issues/929), [jq#2195](https://github.com/stedolan/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/stedolan/jq/issues/1912)). gojq supports nanoseconds in date and time functions.
+- gojq does not support some functions intentionally; `get_jq_origin`, `get_prog_origin`, `get_search_list` (unstable, not listed in jq document), `input_line_number`, `$__loc__` (performance issue), `recurse_down` (deprecated in jq). gojq does not support some flags; `--ascii-output, -a` (performance issue), `--seq` (not used commonly), `--sort-keys, -S` (sorts by default because `map[string]any` does not keep the order), `--unbuffered` (unbuffered by default). gojq does not parse JSON extensions supported by jq; `NaN`, `Infinity`, and `[000]`. gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support or behaves differently with some regular expression metacharacters and flags (regular expression engine differences). gojq does not support BOM (`encoding/json` does not support this). gojq disallows using keywords for function names (`def true: .; true` is a confusing query), and module name prefixes in function declarations (using module prefixes like `def m::f: .;` is undocumented).
- gojq supports reading from YAML input (`--yaml-input`) while jq does not. gojq also supports YAML output (`--yaml-output`).
### Color configuration
@@ -109,7 +109,7 @@ func main() {
if err != nil {
log.Fatalln(err)
}
- input := map[string]interface{}{"foo": []interface{}{1, 2, 3}}
+ input := map[string]any{"foo": []any{1, 2, 3}}
iter := query.Run(input) // or query.RunWithContext
for {
v, ok := iter.Next()
@@ -127,10 +127,10 @@ func main() {
- Firstly, use [`gojq.Parse(string) (*Query, error)`](https://pkg.go.dev/github.com/itchyny/gojq#Parse) to get the query from a string.
- Secondly, get the result iterator
- using [`query.Run`](https://pkg.go.dev/github.com/itchyny/gojq#Query.Run) or [`query.RunWithContext`](https://pkg.go.dev/github.com/itchyny/gojq#Query.RunWithContext)
- - or alternatively, compile the query using [`gojq.Compile`](https://pkg.go.dev/github.com/itchyny/gojq#Compile) and then [`code.Run`](https://pkg.go.dev/github.com/itchyny/gojq#Code.Run) or [`code.RunWithContext`](https://pkg.go.dev/github.com/itchyny/gojq#Code.RunWithContext). You can reuse the `*Code` against multiple inputs to avoid compilation of the same query.
- - In either case, you cannot use custom type values as the query input. The type should be `[]interface{}` for an array and `map[string]interface{}` for a map (just like decoded to an `interface{}` using the [encoding/json](https://golang.org/pkg/encoding/json/) package). You can't use `[]int` or `map[string]string`, for example. If you want to query your custom struct, marshal to JSON, unmarshal to `interface{}` and use it as the query input.
-- Thirdly, iterate through the results using [`iter.Next() (interface{}, bool)`](https://pkg.go.dev/github.com/itchyny/gojq#Iter). The iterator can emit an error so make sure to handle it. The method returns `true` with results, and `false` when the iterator terminates.
- - The return type is not `(interface{}, error)` because iterators can emit multiple errors and you can continue after an error. It is difficult for the iterator to tell the termination in this situation.
+ - or alternatively, compile the query using [`gojq.Compile`](https://pkg.go.dev/github.com/itchyny/gojq#Compile) and then [`code.Run`](https://pkg.go.dev/github.com/itchyny/gojq#Code.Run) or [`code.RunWithContext`](https://pkg.go.dev/github.com/itchyny/gojq#Code.RunWithContext). You can reuse the `*Code` against multiple inputs to avoid compilation of the same query. But for arguments of `code.Run`, do not give values sharing same data between multiple calls.
+ - In either case, you cannot use custom type values as the query input. The type should be `[]any` for an array and `map[string]any` for a map (just like decoded to an `any` using the [encoding/json](https://golang.org/pkg/encoding/json/) package). You can't use `[]int` or `map[string]string`, for example. If you want to query your custom struct, marshal to JSON, unmarshal to `any` and use it as the query input.
+- Thirdly, iterate through the results using [`iter.Next() (any, bool)`](https://pkg.go.dev/github.com/itchyny/gojq#Iter). The iterator can emit an error so make sure to handle it. The method returns `true` with results, and `false` when the iterator terminates.
+ - The return type is not `(any, error)` because iterators can emit multiple errors and you can continue after an error. It is difficult for the iterator to tell the termination in this situation.
- Note that the result iterator may emit infinite number of values; `repeat(0)` and `range(infinite)`. It may stuck with no output value; `def f: f; f`. Use `RunWithContext` when you want to limit the execution time.
[`gojq.Compile`](https://pkg.go.dev/github.com/itchyny/gojq#Compile) allows to configure the following compiler options.
diff --git a/vendor/github.com/itchyny/gojq/_gojq b/vendor/github.com/itchyny/gojq/_gojq
index 4c94718a..d403a314 100644
--- a/vendor/github.com/itchyny/gojq/_gojq
+++ b/vendor/github.com/itchyny/gojq/_gojq
@@ -2,31 +2,42 @@
_gojq()
{
- _arguments -C \
- '(-c --compact-output)'{-c,--compact-output}'[compact output]' \
- '(-r --raw-output)'{-r,--raw-output}'[output raw strings]' \
- '(-j --join-output)'{-j,--join-output}'[stop printing a newline after each output]' \
- '(-0 --nul-output)'{-0,--nul-output}'[print NUL after each output]' \
- '(-C --color-output)'{-C,--color-output}'[colorize output even if piped]' \
- '(-M --monochrome-output)'{-M,--monochrome-output}'[stop colorizing output]' \
- '(--yaml-output)'--yaml-output'[output by YAML]' \
- '(--indent)'--indent'[number of spaces for indentation]:indentation count' \
- '(--tab)'--tab'[use tabs for indentation]' \
+ _arguments -s -S \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-r,--raw-output}'[output raw strings]' \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-j,--join-output}'[output without newlines]' \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-0,--nul-output}'[output with NUL character]' \
+ '(-c --compact-output --indent --tab --yaml-output)'{-c,--compact-output}'[output without pretty-printing]' \
+ '(-c --compact-output --tab --yaml-output)--indent=[number of spaces for indentation]:indentation count:(2 4 8)' \
+ '(-c --compact-output --indent --yaml-output)--tab[use tabs for indentation]' \
+ '(-c --compact-output --indent --tab )--yaml-output[output in YAML format]' \
+ '(-C --color-output -M --monochrome-output)'{-C,--color-output}'[output with colors even if piped]' \
+ '(-C --color-output -M --monochrome-output)'{-M,--monochrome-output}'[output without colors]' \
'(-n --null-input)'{-n,--null-input}'[use null as input value]' \
- '(-R --raw-input)'{-R,--raw-input}'[read input as raw strings]' \
+ '(-R --raw-input --stream --yaml-input)'{-R,--raw-input}'[read input as raw strings]' \
+ '(-R --raw-input --yaml-input)--stream[parse input in stream fashion]' \
+ '(-R --raw-input --stream )--yaml-input[read input as YAML format]' \
'(-s --slurp)'{-s,--slurp}'[read all inputs into an array]' \
- '(--stream)'--stream'[parse input in stream fashion]' \
- '(--yaml-input)'--yaml-input'[read input as YAML]' \
- '(-f --from-file)'{-f,--from-file}'[load query from file]:filename of jq query:_files' \
- '(-L)'-L'[directory to search modules from]:module directory:_directories' \
- '(--arg)'--arg'[set variable to string value]:variable name:' \
- '(--argjson)'--argjson'[set variable to JSON value]:variable name:' \
- '(--slurpfile)'--slurpfile'[set variable to the JSON contents of the file]:variable name:' \
- '(--rawfile)'--rawfile'[set variable to the contents of the file]:variable name:' \
- '(--args)'--args'[consume remaining arguments as positional string values]' \
- '(--jsonargs)'--jsonargs'[consume remaining arguments as positional JSON values]' \
+ '(-f --from-file 1)'{-f,--from-file}='[load query from file]:filename of jq query:_files' \
+ '*-L=[directory to search modules from]:module directory:_directories' \
+ '*--arg[set a string value to a variable]:variable name: :string value' \
+ '*--argjson[set a JSON value to a variable]:variable name: :JSON value' \
+ '*--slurpfile[set the JSON contents of a file to a variable]:variable name: :JSON file:_files' \
+ '*--rawfile[set the contents of a file to a variable]:variable name: :file:_files' \
+ '*--args[consume remaining arguments as positional string values]' \
+ '*--jsonargs[consume remaining arguments as positional JSON values]' \
'(-e --exit-status)'{-e,--exit-status}'[exit 1 when the last value is false or null]' \
- '(-v --version)'{-v,--version}'[print version]' \
- '(-h --help)'{-h,--help}'[print help]' \
- && ret=0
+ '(- 1 *)'{-v,--version}'[display version information]' \
+ '(- 1 *)'{-h,--help}'[display help information]' \
+ '1: :_guard "^-([[:alpha:]0]#|-*)" "jq query"' \
+ '*: :_gojq_args'
+}
+
+_gojq_args() {
+ if (($words[(I)--args] > $words[(I)--jsonargs])); then
+ _message 'string value'
+ elif (($words[(I)--args] < $words[(I)--jsonargs])); then
+ _message 'JSON value'
+ else
+ _arguments '*:input file:_files'
+ fi
}
diff --git a/vendor/github.com/itchyny/gojq/builtin.go b/vendor/github.com/itchyny/gojq/builtin.go
index 65f9e234..ccf31358 100644
--- a/vendor/github.com/itchyny/gojq/builtin.go
+++ b/vendor/github.com/itchyny/gojq/builtin.go
@@ -7,78 +7,61 @@ func init() {
"IN": []*FuncDef{&FuncDef{Name: "IN", Args: []string{"s"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Left: &Query{Func: "s"}, Op: OpEq, Right: &Query{Func: "."}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "IN", Args: []string{"src", "s"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Left: &Query{Func: "src"}, Op: OpEq, Right: &Query{Func: "s"}}, &Query{Func: "."}}}}}}},
"INDEX": []*FuncDef{&FuncDef{Name: "INDEX", Args: []string{"stream", "idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "stream"}}, Pattern: &Pattern{Name: "$row"}, Start: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Left: &Query{Func: "$row"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "idx_expr"}, Op: OpPipe, Right: &Query{Func: "tostring"}}}}}}, Op: OpAssign, Right: &Query{Func: "$row"}}}}}}, &FuncDef{Name: "INDEX", Args: []string{"idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "INDEX", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "idx_expr"}}}}}}},
"JOIN": []*FuncDef{&FuncDef{Name: "JOIN", Args: []string{"$idx", "idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}}}}}}, &FuncDef{Name: "JOIN", Args: []string{"$idx", "stream", "idx_expr"}, Body: &Query{Left: &Query{Func: "stream"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}}}, &FuncDef{Name: "JOIN", Args: []string{"$idx", "stream", "idx_expr", "join_expr"}, Body: &Query{Left: &Query{Func: "stream"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "join_expr"}}}}},
- "all": []*FuncDef{&FuncDef{Name: "all", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "all", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "all", Args: []string{"g", "y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "y"}, Op: OpAnd, Right: &Query{Func: "empty"}}}}}}}}},
- "any": []*FuncDef{&FuncDef{Name: "any", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "any", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "any", Args: []string{"g", "y"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "y"}, Op: OpOr, Right: &Query{Func: "empty"}}}}}}}, Op: OpPipe, Right: &Query{Func: "not"}}}},
+ "_assign": []*FuncDef{},
+ "_modify": []*FuncDef{},
+ "all": []*FuncDef{&FuncDef{Name: "all", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Func: "."}}}}}}, &FuncDef{Name: "all", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "all", Args: []string{"g", "y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "y"}, Op: OpPipe, Right: &Query{Func: "not"}}}}}}}}}}}}},
+ "any": []*FuncDef{&FuncDef{Name: "any", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Func: "."}}}}}}, &FuncDef{Name: "any", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "any", Args: []string{"g", "y"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "y"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "not"}}}},
"arrays": []*FuncDef{&FuncDef{Name: "arrays", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}}}}}}},
- "ascii_downcase": []*FuncDef{&FuncDef{Name: "ascii_downcase", Body: &Query{Left: &Query{Func: "explode"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeNumber, Number: "65"}}, Op: OpLe, Right: &Query{Func: "."}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "90"}}}}, Then: &Query{Left: &Query{Func: "."}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "32"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "implode"}}}}},
- "ascii_upcase": []*FuncDef{&FuncDef{Name: "ascii_upcase", Body: &Query{Left: &Query{Func: "explode"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeNumber, Number: "97"}}, Op: OpLe, Right: &Query{Func: "."}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "122"}}}}, Then: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "32"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "implode"}}}}},
- "assign": []*FuncDef{&FuncDef{Name: "_assign", Args: []string{"ps", "$v"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Func: "."}, Update: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$p"}, &Query{Func: "$v"}}}}}}}}}},
"booleans": []*FuncDef{&FuncDef{Name: "booleans", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "boolean"}}}}}}}}}},
- "capture": []*FuncDef{&FuncDef{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpNe, Right: &Query{Func: "null"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}}}}},
- "combinations": []*FuncDef{&FuncDef{Name: "combinations", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "combinations"}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$y"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$x"}}}}, Op: OpAdd, Right: &Query{Func: "$y"}}}}}}}}}}}}}}}}}, &FuncDef{Name: "combinations", Args: []string{"n"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$dot"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "range", Args: []*Query{&Query{Func: "n"}}}}}, Op: OpPipe, Right: &Query{Func: "$dot"}}}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}}}}}}},
+ "capture": []*FuncDef{&FuncDef{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Func: "_capture"}}}},
+ "combinations": []*FuncDef{&FuncDef{Name: "combinations", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$x"}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}}}}}}}}}}}}, &FuncDef{Name: "combinations", Args: []string{"n"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "limit", Args: []*Query{&Query{Func: "n"}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{&Query{Func: "."}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}},
"del": []*FuncDef{&FuncDef{Name: "del", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "f"}}}}}}}}}}}}}},
- "endswith": []*FuncDef{&FuncDef{Name: "endswith", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Then: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}}}}}, IsSlice: true}}}, Op: OpEq, Right: &Query{Func: "$x"}}, Else: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "endswith"}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "endswith"}}}}}}}}}}}},
"finites": []*FuncDef{&FuncDef{Name: "finites", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "isfinite"}}}}}}},
"first": []*FuncDef{&FuncDef{Name: "first", Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}, &FuncDef{Name: "first", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}},
- "flatten": []*FuncDef{&FuncDef{Name: "_flatten", Args: []string{"$x"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "$x"}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Left: &Query{Func: "$x"}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "."}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "add"}}}, &FuncDef{Name: "flatten", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "flatten depth must not be negative"}}}}}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Func: "$x"}}}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}}, &FuncDef{Name: "flatten", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}},
- "from_entries": []*FuncDef{&FuncDef{Name: "from_entries", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "key"}}}, Op: OpAlt, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Key"}}}, Op: OpAlt, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Name"}}}}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "value"}}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "value"}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Value"}}}}}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}}}},
"fromdate": []*FuncDef{&FuncDef{Name: "fromdate", Body: &Query{Func: "fromdateiso8601"}}},
"fromdateiso8601": []*FuncDef{&FuncDef{Name: "fromdateiso8601", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strptime", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%S%z"}}}}}}}, Op: OpPipe, Right: &Query{Func: "mktime"}}}},
- "fromstream": []*FuncDef{&FuncDef{Name: "fromstream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "x", Val: &ObjectVal{Queries: []*Query{&Query{Func: "null"}}}}, &ObjectKeyVal{Key: "e", Val: &ObjectVal{Queries: []*Query{&Query{Func: "false"}}}}}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$init"}}, Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}, Pattern: &Pattern{Name: "$i"}, Start: &Query{Func: "$init"}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Func: "$init"}, Else: &Query{Func: "."}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$i"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "2"}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "x"}}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "x"}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}},
+ "fromstream": []*FuncDef{&FuncDef{Name: "fromstream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "x", Val: &ObjectVal{Queries: []*Query{&Query{Func: "null"}}}}, &ObjectKeyVal{Key: "e", Val: &ObjectVal{Queries: []*Query{&Query{Func: "false"}}}}}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$init"}}, Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}, Pattern: &Pattern{Name: "$i"}, Start: &Query{Func: "$init"}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Func: "$init"}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$i"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "2"}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "x"}}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "x"}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}},
"group_by": []*FuncDef{&FuncDef{Name: "group_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_group_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
"gsub": []*FuncDef{&FuncDef{Name: "gsub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}, &FuncDef{Name: "gsub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Left: &Query{Func: "$flags"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}}},
"in": []*FuncDef{&FuncDef{Name: "in", Args: []string{"xs"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "xs"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{&Query{Func: "$x"}}}}}}}}}}}}},
- "index": []*FuncDef{&FuncDef{Name: "index", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_lindex", Args: []*Query{&Query{Func: "$x"}}}}}}},
- "indices": []*FuncDef{&FuncDef{Name: "indices", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_indices", Args: []*Query{&Query{Func: "$x"}}}}}}},
"inputs": []*FuncDef{&FuncDef{Name: "inputs", Body: &Query{Term: &Term{Type: TermTypeTry, Try: &Try{Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{&Query{Func: "input"}}}}}, Catch: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "break"}}}}, Then: &Query{Func: "empty"}, Else: &Query{Func: "error"}}}}}}}}},
"inside": []*FuncDef{&FuncDef{Name: "inside", Args: []string{"xs"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "xs"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "contains", Args: []*Query{&Query{Func: "$x"}}}}}}}}}}}}},
"isempty": []*FuncDef{&FuncDef{Name: "isempty", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "false"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}, Op: OpComma, Right: &Query{Func: "true"}}}}}}},
"iterables": []*FuncDef{&FuncDef{Name: "iterables", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpOr, Right: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}}}},
- "join": []*FuncDef{&FuncDef{Name: "join", Args: []string{"$x"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_join", Args: []*Query{&Query{Func: "$x"}}}}}}}},
"last": []*FuncDef{&FuncDef{Name: "last", Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}, &FuncDef{Name: "last", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "null"}, Update: &Query{Func: "$item"}}}}}},
"leaf_paths": []*FuncDef{&FuncDef{Name: "leaf_paths", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "paths", Args: []*Query{&Query{Func: "scalars"}}}}}}},
"limit": []*FuncDef{&FuncDef{Name: "limit", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "$n"}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}, Else: &Query{Func: "empty"}}}}}}}}}}}, Elif: []*IfElif{&IfElif{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Func: "empty"}}}, Else: &Query{Func: "g"}}}}}},
- "ltrimstr": []*FuncDef{&FuncDef{Name: "ltrimstr", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "startswith", Args: []*Query{&Query{Func: "$x"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}, IsSlice: true}}}}}}}},
"map": []*FuncDef{&FuncDef{Name: "map", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}},
"map_values": []*FuncDef{&FuncDef{Name: "map_values", Args: []string{"f"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpModify, Right: &Query{Func: "f"}}}},
- "match": []*FuncDef{&FuncDef{Name: "match", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "match", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}, &Query{Func: "false"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}},
- "max": []*FuncDef{&FuncDef{Name: "max", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "max_by", Args: []*Query{&Query{Func: "."}}}}}}},
+ "match": []*FuncDef{&FuncDef{Name: "match", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "match", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}, &Query{Func: "false"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}},
"max_by": []*FuncDef{&FuncDef{Name: "max_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_max_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
- "min": []*FuncDef{&FuncDef{Name: "min", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "min_by", Args: []*Query{&Query{Func: "."}}}}}}},
"min_by": []*FuncDef{&FuncDef{Name: "min_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_min_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
- "modify": []*FuncDef{&FuncDef{Name: "_modify", Args: []string{"ps", "f"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}, Update: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpAdd, Right: &Query{Func: "$p"}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$q"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$q"}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$q"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}}}}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$p"}}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}}}}}}}}},
"normals": []*FuncDef{&FuncDef{Name: "normals", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "isnormal"}}}}}}},
"not": []*FuncDef{&FuncDef{Name: "not", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "."}, Then: &Query{Func: "false"}, Else: &Query{Func: "true"}}}}}},
- "nth": []*FuncDef{&FuncDef{Name: "nth", Args: []string{"$n"}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}}}}}, &FuncDef{Name: "nth", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "nth doesn't support negative indices"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "$n"}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Op: OpOr, Right: &Query{Func: "empty"}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}}}}}}}},
+ "nth": []*FuncDef{&FuncDef{Name: "nth", Args: []string{"$n"}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}}}}}, &FuncDef{Name: "nth", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "nth doesn't support negative indices"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Left: &Query{Func: "$n"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}}},
"nulls": []*FuncDef{&FuncDef{Name: "nulls", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Func: "null"}}}}}}}},
"numbers": []*FuncDef{&FuncDef{Name: "numbers", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "number"}}}}}}}}}},
"objects": []*FuncDef{&FuncDef{Name: "objects", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}},
- "paths": []*FuncDef{&FuncDef{Name: "paths", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "recurse", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpOr, Right: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}}, &FuncDef{Name: "paths", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "paths"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}}}}}}}}}}}}}}},
+ "paths": []*FuncDef{&FuncDef{Name: "paths", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: ".."}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}}}}, &FuncDef{Name: "paths", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "paths"}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}, Op: OpPipe, Right: &Query{Func: "$p"}}}}}}}}},
"range": []*FuncDef{&FuncDef{Name: "range", Args: []string{"$end"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, &Query{Func: "$end"}, &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, &FuncDef{Name: "range", Args: []string{"$start", "$end"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Func: "$start"}, &Query{Func: "$end"}, &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, &FuncDef{Name: "range", Args: []string{"$start", "$end", "$step"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Func: "$start"}, &Query{Func: "$end"}, &Query{Func: "$step"}}}}}}},
"recurse": []*FuncDef{&FuncDef{Name: "recurse", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "recurse", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}}}}}}, &FuncDef{Name: "recurse", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Func: "r"}}}}}}}, Func: "r"}}, &FuncDef{Name: "recurse", Args: []string{"f", "cond"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "cond"}}}}}, Op: OpPipe, Right: &Query{Func: "r"}}}}}}}}, Func: "r"}}},
"repeat": []*FuncDef{&FuncDef{Name: "repeat", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_repeat", Body: &Query{Left: &Query{Func: "f"}, Op: OpComma, Right: &Query{Func: "_repeat"}}}}, Func: "_repeat"}}},
- "rindex": []*FuncDef{&FuncDef{Name: "rindex", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_rindex", Args: []*Query{&Query{Func: "$x"}}}}}}},
- "rtrimstr": []*FuncDef{&FuncDef{Name: "rtrimstr", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "endswith", Args: []*Query{&Query{Func: "$x"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{End: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}}}}}, IsSlice: true}}}}}}}},
"scalars": []*FuncDef{&FuncDef{Name: "scalars", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}}}},
- "scan": []*FuncDef{&FuncDef{Name: "scan", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "scan", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "scan", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Left: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}, Op: OpAdd, Right: &Query{Func: "$flags"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Index: &Index{Name: "string"}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}},
+ "scan": []*FuncDef{&FuncDef{Name: "scan", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "scan", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "scan", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Left: &Query{Func: "$flags"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}}}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}, Else: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Index: &Index{Name: "string"}}}}}}}}}}}}}},
"select": []*FuncDef{&FuncDef{Name: "select", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "f"}, Then: &Query{Func: "."}, Else: &Query{Func: "empty"}}}}}},
- "sort": []*FuncDef{&FuncDef{Name: "sort", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sort_by", Args: []*Query{&Query{Func: "."}}}}}}},
"sort_by": []*FuncDef{&FuncDef{Name: "sort_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_sort_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
- "splits": []*FuncDef{&FuncDef{Name: "splits", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "splits", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "split", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}},
- "startswith": []*FuncDef{&FuncDef{Name: "startswith", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Then: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{End: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}, IsSlice: true}}}, Op: OpEq, Right: &Query{Func: "$x"}}, Else: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "startswith"}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "startswith"}}}}}}}}}}}},
+ "splits": []*FuncDef{&FuncDef{Name: "splits", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "splits", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "split", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}},
"strings": []*FuncDef{&FuncDef{Name: "strings", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}}},
- "sub": []*FuncDef{&FuncDef{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$in"}}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_sub", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$r"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "captures"}}, &Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpNe, Right: &Query{Func: "null"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "string"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$in"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, End: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, IsSlice: true}}}}}}, Op: OpAdd, Right: &Query{Func: "str"}}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "length"}}}}}}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "matches"}}, &Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}}}}}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$in"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}}}}}}}, Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}},
+ "sub": []*FuncDef{&FuncDef{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$str"}}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_sub", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}}}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{&Suffix{Index: &Index{End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$r"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$r"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "_capture"}, Op: OpPipe, Right: &Query{Func: "str"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "length"}}}}}}, End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{End: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}, IsSlice: true}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}}}}}, Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}},
"test": []*FuncDef{&FuncDef{Name: "test", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "test", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "test", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}, &Query{Func: "true"}}}}}}},
- "to_entries": []*FuncDef{&FuncDef{Name: "to_entries", Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "keys"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$k"}}, Body: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "key", Val: &ObjectVal{Queries: []*Query{&Query{Func: "$k"}}}}, &ObjectKeyVal{Key: "value", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$k"}}}}}}}}}}}}}}}}}}}}},
"todate": []*FuncDef{&FuncDef{Name: "todate", Body: &Query{Func: "todateiso8601"}}},
"todateiso8601": []*FuncDef{&FuncDef{Name: "todateiso8601", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strftime", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%SZ"}}}}}}}}},
"tostream": []*FuncDef{&FuncDef{Name: "tostream", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}, Op: OpPipe, Right: &Query{Func: "r"}}}}, Op: OpComma, Right: &Query{Func: "."}}}}, Func: "r"}}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}}}}, Pattern: &Pattern{Name: "$q"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "$p"}, Op: OpComma, Right: &Query{Func: "."}}}}}, Update: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "$p"}, Op: OpAdd, Right: &Query{Func: "$q"}}}}}}}}}}}}}}}},
- "truncate_stream": []*FuncDef{&FuncDef{Name: "truncate_stream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$n"}}, Body: &Query{Left: &Query{Func: "null"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$input"}}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpPipe, Right: &Query{Func: "length"}}}}, Op: OpGt, Right: &Query{Func: "$n"}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$input"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, &Suffix{Index: &Index{Start: &Query{Func: "$n"}, IsSlice: true}}}}}}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}}}}}},
- "unique": []*FuncDef{&FuncDef{Name: "unique", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "unique_by", Args: []*Query{&Query{Func: "."}}}}}}},
+ "truncate_stream": []*FuncDef{&FuncDef{Name: "truncate_stream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$n"}}, Body: &Query{Left: &Query{Func: "null"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Func: "$n"}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpModify, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}, IsSlice: true}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}},
"unique_by": []*FuncDef{&FuncDef{Name: "unique_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_unique_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
"until": []*FuncDef{&FuncDef{Name: "until", Args: []string{"cond", "next"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_until", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "cond"}, Then: &Query{Func: "."}, Else: &Query{Left: &Query{Func: "next"}, Op: OpPipe, Right: &Query{Func: "_until"}}}}}}}, Func: "_until"}}},
"values": []*FuncDef{&FuncDef{Name: "values", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Func: "null"}}}}}}}},
- "walk": []*FuncDef{&FuncDef{Name: "walk", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_walk", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpOr, Right: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map_values", Args: []*Query{&Query{Func: "_walk"}}}}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}, Func: "_walk"}}},
+ "walk": []*FuncDef{&FuncDef{Name: "walk", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_walk", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Func: "_walk"}}}}}, Elif: []*IfElif{&IfElif{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map_values", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "last", Args: []*Query{&Query{Func: "_walk"}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}, Func: "_walk"}}},
"while": []*FuncDef{&FuncDef{Name: "while", Args: []string{"cond", "update"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_while", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "cond"}, Then: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "update"}, Op: OpPipe, Right: &Query{Func: "_while"}}}}}, Else: &Query{Func: "empty"}}}}}}, Func: "_while"}}},
"with_entries": []*FuncDef{&FuncDef{Name: "with_entries", Args: []string{"f"}, Body: &Query{Left: &Query{Func: "to_entries"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Func: "f"}}}}}, Op: OpPipe, Right: &Query{Func: "from_entries"}}}}},
}
diff --git a/vendor/github.com/itchyny/gojq/builtin.jq b/vendor/github.com/itchyny/gojq/builtin.jq
index b6a9e1d8..66d63073 100644
--- a/vendor/github.com/itchyny/gojq/builtin.jq
+++ b/vendor/github.com/itchyny/gojq/builtin.jq
@@ -1,10 +1,6 @@
def not: if . then false else true end;
def in(xs): . as $x | xs | has($x);
def map(f): [.[] | f];
-def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];
-def from_entries:
- map({ (.key // .Key // .name // .Name): (if has("value") then .value else .Value end) })
- | add // {};
def with_entries(f): to_entries | map(f) | from_entries;
def select(f): if f then . else empty end;
def recurse: recurse(.[]?);
@@ -24,21 +20,10 @@ def range($end): _range(0; $end; 1);
def range($start; $end): _range($start; $end; 1);
def range($start; $end; $step): _range($start; $end; $step);
-def _flatten($x):
- map(if type == "array" and $x != 0 then _flatten($x - 1) else [.] end) | add;
-def flatten($x):
- if $x < 0
- then error("flatten depth must not be negative")
- else _flatten($x) // [] end;
-def flatten: _flatten(-1) // [];
-def min: min_by(.);
def min_by(f): _min_by(map([f]));
-def max: max_by(.);
def max_by(f): _max_by(map([f]));
-def sort: sort_by(.);
def sort_by(f): _sort_by(map([f]));
def group_by(f): _group_by(map([f]));
-def unique: unique_by(.);
def unique_by(f): _unique_by(map([f]));
def arrays: select(type == "array");
@@ -54,55 +39,21 @@ def values: select(. != null);
def scalars: select(type | . != "array" and . != "object");
def leaf_paths: paths(scalars);
-def indices($x): _indices($x);
-def index($x): _lindex($x);
-def rindex($x): _rindex($x);
def inside(xs): . as $x | xs | contains($x);
-def startswith($x):
- if type == "string" then
- if $x|type == "string" then
- .[:$x | length] == $x
- else
- $x | _type_error("startswith")
- end
- else
- _type_error("startswith")
- end;
-def endswith($x):
- if type == "string" then
- if $x|type == "string" then
- .[- ($x | length):] == $x
- else
- $x | _type_error("endswith")
- end
- else
- _type_error("endswith")
- end;
-def ltrimstr($x):
- if type == "string" and ($x|type == "string") and startswith($x) then
- .[$x | length:]
- end;
-def rtrimstr($x):
- if type == "string" and ($x|type == "string") and endswith($x) then
- .[:- ($x | length)]
- end;
-
def combinations:
if length == 0 then
[]
else
- .[0][] as $x | .[1:] | combinations as $y | [$x] + $y
+ .[0][] as $x | [$x] + (.[1:] | combinations)
end;
-def combinations(n):
- . as $dot | [range(n) | $dot] | combinations;
-def join($x):
- if type != "array" then [.[]] end | _join($x);
-def ascii_downcase:
- explode | map(if 65 <= . and . <= 90 then . + 32 end) | implode;
-def ascii_upcase:
- explode | map(if 97 <= . and . <= 122 then . - 32 end) | implode;
+def combinations(n): [limit(n; repeat(.))] | combinations;
def walk(f):
- def _walk: if type | . == "array" or . == "object" then map_values(_walk) end | f;
+ def _walk:
+ if type == "array" then
+ map(_walk)
+ elif type == "object" then
+ map_values(last(_walk))
+ end | f;
_walk;
def first: .[0];
@@ -110,17 +61,20 @@ def first(g): label $out | g | ., break $out;
def last: .[-1];
def last(g): reduce g as $item (null; $item);
def isempty(g): label $out | (g | false, break $out), true;
-def all: all(.[]; .);
+def all: all(.);
def all(y): all(.[]; y);
-def all(g; y): isempty(g|y and empty);
-def any: any(.[]; .);
+def all(g; y): isempty(g | select(y | not));
+def any: any(.);
def any(y): any(.[]; y);
-def any(g; y): isempty(g|y or empty) | not;
+def any(g; y): isempty(g | select(y)) | not;
def limit($n; g):
if $n > 0 then
- label $out
- | foreach g as $item
- ($n; .-1; $item, if . <= 0 then break $out else empty end)
+ label $out |
+ foreach g as $item (
+ $n;
+ . - 1;
+ $item, if . <= 0 then break $out else empty end
+ )
elif $n == 0 then
empty
else
@@ -131,41 +85,39 @@ def nth($n; g):
if $n < 0 then
error("nth doesn't support negative indices")
else
- label $out
- | foreach g as $item
- ($n; .-1; . < 0 or empty | $item, break $out)
+ label $out |
+ foreach g as $item (
+ $n + 1;
+ . - 1;
+ if . <= 0 then $item, break $out else empty end
+ )
end;
def truncate_stream(f):
- . as $n | null | f | . as $input
- | if (.[0] | length) > $n then setpath([0]; $input[0][$n:]) else empty end;
+ . as $n | null | f |
+ if .[0] | length > $n then .[0] |= .[$n:] else empty end;
def fromstream(f):
- { x: null, e: false } as $init
- | foreach f as $i
- ( $init;
- if .e then $init else . end
- | if $i | length == 2
- then setpath(["e"]; $i[0] | length==0) | setpath(["x"] + $i[0]; $i[1])
- else setpath(["e"]; $i[0] | length==1) end;
- if .e then .x else empty end);
+ { x: null, e: false } as $init |
+ foreach f as $i (
+ $init;
+ if .e then $init end |
+ if $i | length == 2 then
+ setpath(["e"]; $i[0] | length == 0) |
+ setpath(["x"] + $i[0]; $i[1])
+ else
+ setpath(["e"]; $i[0] | length == 1)
+ end;
+ if .e then .x else empty end
+ );
def tostream:
- path(def r: (.[]? | r), .; r) as $p
- | getpath($p)
- | reduce path(.[]?) as $q ([$p, .]; [$p + $q]);
+ path(def r: (.[]? | r), .; r) as $p |
+ getpath($p) |
+ reduce path(.[]?) as $q ([$p, .]; [$p + $q]);
-def _assign(ps; $v):
- reduce path(ps) as $p (.; setpath($p; $v));
-def _modify(ps; f):
- reduce path(ps) as $p
- ([., []]; label $out | (([0] + $p) as $q | setpath($q; getpath($q) | f) | ., break $out), setpath([1]; .[1] + [$p]))
- | . as $x | $x[0] | delpaths($x[1]);
def map_values(f): .[] |= f;
def del(f): delpaths([path(f)]);
-def paths:
- path(recurse(if type | . == "array" or . == "object" then .[] else empty end))
- | select(length > 0);
-def paths(f):
- . as $x | paths | select(. as $p | $x | getpath($p) | f);
+def paths: path(..) | select(. != []);
+def paths(f): paths as $p | select(getpath($p) | f) | $p;
def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%S%z") | mktime;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
@@ -173,39 +125,37 @@ def fromdate: fromdateiso8601;
def todate: todateiso8601;
def match($re): match($re; null);
-def match($re; $flags): _match($re; $flags; false) | .[];
+def match($re; $flags): _match($re; $flags; false)[];
def test($re): test($re; null);
def test($re; $flags): _match($re; $flags; true);
def capture($re): capture($re; null);
-def capture($re; $flags):
- match($re; $flags)
- | [.captures[] | select(.name != null) | { (.name): .string }]
- | add // {};
+def capture($re; $flags): match($re; $flags) | _capture;
def scan($re): scan($re; null);
def scan($re; $flags):
- match($re; "g" + $flags)
- | if .captures|length > 0 then [.captures[].string] else .string end;
+ match($re; $flags + "g") |
+ if .captures == [] then
+ .string
+ else
+ [.captures[].string]
+ end;
def splits($re): splits($re; null);
-def splits($re; $flags): split($re; $flags) | .[];
+def splits($re; $flags): split($re; $flags)[];
def sub($re; str): sub($re; str; null);
def sub($re; str; $flags):
- . as $in
- | def _sub:
- if .matches|length > 0
- then
- . as $x | .matches[0] as $r
- | [$r.captures[] | select(.name != null) | { (.name): .string }]
- | add // {}
- | {
- string: ($x.string + $in[$x.offset:$r.offset] + str),
- offset: ($r.offset + $r.length),
- matches: $x.matches[1:]
- }
- | _sub
- else
- .string + $in[.offset:]
- end;
- { string: "", offset: 0, matches: [match($re; $flags)] } | _sub;
+ . as $str |
+ def _sub:
+ if .matches == [] then
+ $str[:.offset] + .string
+ else
+ .matches[-1] as $r |
+ {
+ string: (($r | _capture | str) + $str[$r.offset+$r.length:.offset] + .string),
+ offset: $r.offset,
+ matches: .matches[:-1],
+ } |
+ _sub
+ end;
+ { string: "", matches: [match($re; $flags)] } | _sub;
def gsub($re; str): sub($re; str; "g");
def gsub($re; str; $flags): sub($re; str; $flags + "g");
@@ -216,8 +166,9 @@ def inputs:
if . == "break" then empty else error end;
def INDEX(stream; idx_expr):
- reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row);
-def INDEX(idx_expr): INDEX(.[]; idx_expr);
+ reduce stream as $row ({}; .[$row | idx_expr | tostring] = $row);
+def INDEX(idx_expr):
+ INDEX(.[]; idx_expr);
def JOIN($idx; idx_expr):
[.[] | [., $idx[idx_expr]]];
def JOIN($idx; stream; idx_expr):
diff --git a/vendor/github.com/itchyny/gojq/code.go b/vendor/github.com/itchyny/gojq/code.go
index f1935d84..33505bde 100644
--- a/vendor/github.com/itchyny/gojq/code.go
+++ b/vendor/github.com/itchyny/gojq/code.go
@@ -1,7 +1,7 @@
package gojq
type code struct {
- v interface{}
+ v any
op opcode
}
@@ -25,13 +25,15 @@ const (
opbacktrack
opjump
opjumpifnot
+ opindex
+ opindexarray
opcall
opcallrec
oppushpc
opcallpc
opscope
opret
- opeach
+ opiter
opexpbegin
opexpend
oppathbegin
@@ -74,6 +76,10 @@ func (op opcode) String() string {
return "jump"
case opjumpifnot:
return "jumpifnot"
+ case opindex:
+ return "index"
+ case opindexarray:
+ return "indexarray"
case opcall:
return "call"
case opcallrec:
@@ -86,8 +92,8 @@ func (op opcode) String() string {
return "scope"
case opret:
return "ret"
- case opeach:
- return "each"
+ case opiter:
+ return "iter"
case opexpbegin:
return "expbegin"
case opexpend:
diff --git a/vendor/github.com/itchyny/gojq/compare.go b/vendor/github.com/itchyny/gojq/compare.go
index 9f0d5338..e70c1fbb 100644
--- a/vendor/github.com/itchyny/gojq/compare.go
+++ b/vendor/github.com/itchyny/gojq/compare.go
@@ -5,19 +5,17 @@ import (
"math/big"
)
-func compare(l, r interface{}) int {
+// Compare l and r, and returns jq-flavored comparison value.
+// The result will be 0 if l == r, -1 if l < r, and +1 if l > r.
+// This comparison is used by built-in operators and functions.
+func Compare(l, r any) int {
+ return compare(l, r)
+}
+
+func compare(l, r any) int {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
- switch {
- case l < r:
- return -1
- case l == r:
- return 0
- default:
- return 1
- }
- },
- func(l, r float64) interface{} {
+ compareInt,
+ func(l, r float64) any {
switch {
case l < r || math.IsNaN(l):
return -1
@@ -27,10 +25,10 @@ func compare(l, r interface{}) int {
return 1
}
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
return l.Cmp(r)
},
- func(l, r string) interface{} {
+ func(l, r string) any {
switch {
case l < r:
return -1
@@ -40,66 +38,63 @@ func compare(l, r interface{}) int {
return 1
}
},
- func(l, r []interface{}) interface{} {
- for i := 0; ; i++ {
- if i >= len(l) {
- if i >= len(r) {
- return 0
- }
- return -1
- }
- if i >= len(r) {
- return 1
- }
+ func(l, r []any) any {
+ n := len(l)
+ if len(r) < n {
+ n = len(r)
+ }
+ for i := 0; i < n; i++ {
if cmp := compare(l[i], r[i]); cmp != 0 {
return cmp
}
}
+ return compareInt(len(l), len(r))
},
- func(l, r map[string]interface{}) interface{} {
+ func(l, r map[string]any) any {
lk, rk := funcKeys(l), funcKeys(r)
if cmp := compare(lk, rk); cmp != 0 {
return cmp
}
- for _, k := range lk.([]interface{}) {
+ for _, k := range lk.([]any) {
if cmp := compare(l[k.(string)], r[k.(string)]); cmp != 0 {
return cmp
}
}
return 0
},
- func(l, r interface{}) interface{} {
- ln, rn := getTypeOrdNum(l), getTypeOrdNum(r)
- switch {
- case ln < rn:
- return -1
- case ln == rn:
- return 0
- default:
- return 1
- }
+ func(l, r any) any {
+ return compareInt(typeIndex(l), typeIndex(r))
},
).(int)
}
-func getTypeOrdNum(v interface{}) int {
+func compareInt(l, r int) any {
+ switch {
+ case l < r:
+ return -1
+ case l == r:
+ return 0
+ default:
+ return 1
+ }
+}
+
+func typeIndex(v any) int {
switch v := v.(type) {
- case nil:
+ default:
return 0
case bool:
- if v {
- return 2
+ if !v {
+ return 1
}
- return 1
+ return 2
case int, float64, *big.Int:
return 3
case string:
return 4
- case []interface{}:
+ case []any:
return 5
- case map[string]interface{}:
+ case map[string]any:
return 6
- default:
- return -1
}
}
diff --git a/vendor/github.com/itchyny/gojq/compiler.go b/vendor/github.com/itchyny/gojq/compiler.go
index 00daa04c..135387fa 100644
--- a/vendor/github.com/itchyny/gojq/compiler.go
+++ b/vendor/github.com/itchyny/gojq/compiler.go
@@ -2,7 +2,6 @@ package gojq
import (
"context"
- "encoding/json"
"errors"
"fmt"
"sort"
@@ -18,6 +17,7 @@ type compiler struct {
inputIter Iter
codes []*code
codeinfos []codeinfo
+ builtinScope *scopeinfo
scopes []*scopeinfo
scopecnt int
}
@@ -30,16 +30,17 @@ type Code struct {
}
// Run runs the code with the variable values (which should be in the
-// same order as the given variables using WithVariables) and returns
+// same order as the given variables using [WithVariables]) and returns
// a result iterator.
//
-// It is safe to call this method of a *Code in multiple goroutines.
-func (c *Code) Run(v interface{}, values ...interface{}) Iter {
+// It is safe to call this method in goroutines, to reuse a compiled [*Code].
+// But for arguments, do not give values sharing same data between goroutines.
+func (c *Code) Run(v any, values ...any) Iter {
return c.RunWithContext(context.Background(), v, values...)
}
// RunWithContext runs the code with context.
-func (c *Code) RunWithContext(ctx context.Context, v interface{}, values ...interface{}) Iter {
+func (c *Code) RunWithContext(ctx context.Context, v any, values ...any) Iter {
if len(values) > len(c.variables) {
return NewIter(&tooManyVariableValuesError{})
} else if len(values) < len(c.variables) {
@@ -51,16 +52,6 @@ func (c *Code) RunWithContext(ctx context.Context, v interface{}, values ...inte
return newEnv(ctx).execute(c, normalizeNumbers(v), values...)
}
-// ModuleLoader is an interface for loading modules.
-//
-// Implement following optional methods. Use NewModuleLoader to load local modules.
-// LoadModule(string) (*Query, error)
-// LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
-// LoadInitModules() ([]*Query, error)
-// LoadJSON(string) (interface{}, error)
-// LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error)
-type ModuleLoader interface{}
-
type scopeinfo struct {
variables []*varinfo
funcs []*funcinfo
@@ -87,6 +78,7 @@ func Compile(q *Query, options ...CompilerOption) (*Code, error) {
for _, opt := range options {
opt(c)
}
+ c.builtinScope = c.newScope()
scope := c.newScope()
c.scopes = []*scopeinfo{scope}
setscope := c.lazy(func() *code {
@@ -152,15 +144,15 @@ func (c *compiler) compileImport(i *Import) error {
return fmt.Errorf("cannot load module: %q", path)
}
if strings.HasPrefix(alias, "$") {
- var vals interface{}
+ var vals any
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error)
+ LoadJSONWithMeta(string, map[string]any) (any, error)
}); ok {
if vals, err = moduleLoader.LoadJSONWithMeta(path, i.Meta.ToValue()); err != nil {
return err
}
} else if moduleLoader, ok := c.moduleLoader.(interface {
- LoadJSON(string) (interface{}, error)
+ LoadJSON(string) (any, error)
}); ok {
if vals, err = moduleLoader.LoadJSON(path); err != nil {
return err
@@ -177,7 +169,7 @@ func (c *compiler) compileImport(i *Import) error {
}
var q *Query
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
+ LoadModuleWithMeta(string, map[string]any) (*Query, error)
}); ok {
if q, err = moduleLoader.LoadModuleWithMeta(path, i.Meta.ToValue()); err != nil {
return err
@@ -190,8 +182,11 @@ func (c *compiler) compileImport(i *Import) error {
}
}
c.appendCodeInfo("module " + path)
- defer c.appendCodeInfo("end of module " + path)
- return c.compileModule(q, alias)
+ if err = c.compileModule(q, alias); err != nil {
+ return err
+ }
+ c.appendCodeInfo("end of module " + path)
+ return nil
}
func (c *compiler) compileModule(q *Query, alias string) error {
@@ -274,6 +269,31 @@ func (c *compiler) lookupFuncOrVariable(name string) (*funcinfo, *varinfo) {
return nil, nil
}
+func (c *compiler) lookupBuiltin(name string, argcnt int) *funcinfo {
+ s := c.builtinScope
+ for i := len(s.funcs) - 1; i >= 0; i-- {
+ if f := s.funcs[i]; f.name == name && f.argcnt == argcnt {
+ return f
+ }
+ }
+ return nil
+}
+
+func (c *compiler) appendBuiltin(name string, argcnt int) func() {
+ setjump := c.lazy(func() *code {
+ return &code{op: opjump, v: len(c.codes)}
+ })
+ c.appendCodeInfo(name)
+ c.builtinScope.funcs = append(
+ c.builtinScope.funcs,
+ &funcinfo{name, len(c.codes), argcnt},
+ )
+ return func() {
+ setjump()
+ c.appendCodeInfo("end of " + name)
+ }
+}
+
func (c *compiler) newScope() *scopeinfo {
i := c.scopecnt // do not use len(c.scopes) because it pops
c.scopecnt++
@@ -294,29 +314,22 @@ func (c *compiler) newScopeDepth() func() {
func (c *compiler) compileFuncDef(e *FuncDef, builtin bool) error {
var scope *scopeinfo
if builtin {
- scope = c.scopes[0]
- for i := len(scope.funcs) - 1; i >= 0; i-- {
- if f := scope.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) {
- return nil
- }
- }
+ scope = c.builtinScope
} else {
scope = c.scopes[len(c.scopes)-1]
}
defer c.lazy(func() *code {
- return &code{op: opjump, v: c.pc()}
+ return &code{op: opjump, v: len(c.codes)}
})()
c.appendCodeInfo(e.Name)
- defer c.appendCodeInfo("end of " + e.Name)
- pc := c.pc()
- scope.funcs = append(scope.funcs, &funcinfo{e.Name, pc, len(e.Args)})
+ scope.funcs = append(scope.funcs, &funcinfo{e.Name, len(c.codes), len(e.Args)})
defer func(scopes []*scopeinfo, variables []string) {
c.scopes, c.variables = scopes, variables
}(c.scopes, c.variables)
c.variables = c.variables[len(c.variables):]
scope = c.newScope()
if builtin {
- c.scopes = []*scopeinfo{c.scopes[0], scope}
+ c.scopes = []*scopeinfo{c.builtinScope, scope}
} else {
c.scopes = append(c.scopes, scope)
}
@@ -344,14 +357,20 @@ func (c *compiler) compileFuncDef(e *FuncDef, builtin bool) error {
}
for _, w := range vis {
c.append(&code{op: opload, v: v})
+ c.append(&code{op: opexpbegin})
c.append(&code{op: opload, v: w.index})
c.append(&code{op: opcallpc})
c.appendCodeInfo(w.name)
c.append(&code{op: opstore, v: c.pushVariable(w.name)})
+ c.append(&code{op: opexpend})
}
c.append(&code{op: opload, v: v})
}
- return c.compile(e.Body)
+ if err := c.compile(e.Body); err != nil {
+ return err
+ }
+ c.appendCodeInfo("end of " + e.Name)
+ return nil
}
func (c *compiler) compileQuery(e *Query) error {
@@ -425,15 +444,15 @@ func (c *compiler) compileQuery(e *Query) error {
func (c *compiler) compileComma(l, r *Query) error {
setfork := c.lazy(func() *code {
- return &code{op: opfork, v: c.pc() + 1}
+ return &code{op: opfork, v: len(c.codes)}
})
if err := c.compileQuery(l); err != nil {
return err
}
- setfork()
defer c.lazy(func() *code {
- return &code{op: opjump, v: c.pc()}
+ return &code{op: opjump, v: len(c.codes)}
})()
+ setfork()
return c.compileQuery(r)
}
@@ -442,23 +461,23 @@ func (c *compiler) compileAlt(l, r *Query) error {
found := c.newVariable()
c.append(&code{op: opstore, v: found})
setfork := c.lazy(func() *code {
- return &code{op: opfork, v: c.pc()} // opload found
+ return &code{op: opfork, v: len(c.codes)} // opload found
})
if err := c.compileQuery(l); err != nil {
return err
}
c.append(&code{op: opdup})
- c.append(&code{op: opjumpifnot, v: c.pc() + 4}) // oppop
- c.append(&code{op: oppush, v: true}) // found some value
+ c.append(&code{op: opjumpifnot, v: len(c.codes) + 4}) // oppop
+ c.append(&code{op: oppush, v: true}) // found some value
c.append(&code{op: opstore, v: found})
defer c.lazy(func() *code {
- return &code{op: opjump, v: c.pc()} // ret
+ return &code{op: opjump, v: len(c.codes)}
})()
c.append(&code{op: oppop})
c.append(&code{op: opbacktrack})
setfork()
c.append(&code{op: opload, v: found})
- c.append(&code{op: opjumpifnot, v: c.pc() + 3})
+ c.append(&code{op: opjumpifnot, v: len(c.codes) + 3})
c.append(&code{op: opbacktrack}) // if found, backtrack
c.append(&code{op: oppop})
return c.compileQuery(r)
@@ -467,8 +486,9 @@ func (c *compiler) compileAlt(l, r *Query) error {
func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
switch op {
case OpAssign:
- // .foo.bar = f => setpath(["foo", "bar"]; f)
- if xs := l.toIndices(); xs != nil {
+ // optimize assignment operator with constant indexing and slicing
+ // .foo.[0].[1:2] = f => setpath(["foo",0,{"start":1,"end":2}]; f)
+ if xs := l.toIndices(nil); xs != nil {
// ref: compileCall
v := c.newVariable()
c.append(&code{op: opstore, v: v})
@@ -478,7 +498,7 @@ func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
}
c.append(&code{op: oppush, v: xs})
c.append(&code{op: opload, v: v})
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["setpath"].callback, 2, "setpath"}})
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["setpath"].callback, 2, "setpath"}})
return nil
}
fallthrough
@@ -517,7 +537,12 @@ func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
}
}
-func (c *compiler) compileBind(b *Bind) error {
+func (c *compiler) compileBind(e *Term, b *Bind) error {
+ c.append(&code{op: opdup})
+ c.append(&code{op: opexpbegin})
+ if err := c.compileTerm(e); err != nil {
+ return err
+ }
var pc int
var vs [][2]int
for i, p := range b.Patterns {
@@ -534,97 +559,86 @@ func (c *compiler) compileBind(b *Bind) error {
c.append(&code{op: opstore, v: v})
}
}
- vs, err = c.compilePattern(p)
- if err != nil {
+ if vs, err = c.compilePattern(vs[:0], p); err != nil {
return err
}
if i < len(b.Patterns)-1 {
defer c.lazy(func() *code {
return &code{op: opjump, v: pc}
})()
- pcc = c.pc()
+ pcc = len(c.codes)
}
}
if len(b.Patterns) > 1 {
- pc = c.pc()
+ pc = len(c.codes)
}
if len(b.Patterns) == 1 && c.codes[len(c.codes)-2].op == opexpbegin {
c.codes[len(c.codes)-2].op = opnop
} else {
- c.append(&code{op: opexpend}) // ref: compileTermSuffix
+ c.append(&code{op: opexpend})
}
return c.compileQuery(b.Body)
}
-func (c *compiler) compilePattern(p *Pattern) ([][2]int, error) {
+func (c *compiler) compilePattern(vs [][2]int, p *Pattern) ([][2]int, error) {
+ var err error
c.appendCodeInfo(p)
if p.Name != "" {
v := c.pushVariable(p.Name)
c.append(&code{op: opstore, v: v})
- return [][2]int{v}, nil
+ return append(vs, v), nil
} else if len(p.Array) > 0 {
- var vs [][2]int
v := c.newVariable()
c.append(&code{op: opstore, v: v})
for i, p := range p.Array {
- c.append(&code{op: oppush, v: i})
- c.append(&code{op: opload, v: v})
c.append(&code{op: opload, v: v})
- // ref: compileCall
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
- ns, err := c.compilePattern(p)
- if err != nil {
+ c.append(&code{op: opindexarray, v: i})
+ if vs, err = c.compilePattern(vs, p); err != nil {
return nil, err
}
- vs = append(vs, ns...)
}
return vs, nil
} else if len(p.Object) > 0 {
- var vs [][2]int
v := c.newVariable()
c.append(&code{op: opstore, v: v})
for _, kv := range p.Object {
var key, name string
- if kv.KeyOnly != "" {
- key, name = kv.KeyOnly[1:], kv.KeyOnly
- c.append(&code{op: oppush, v: key})
- } else if kv.Key != "" {
- key = kv.Key
- if key != "" && key[0] == '$' {
+ c.append(&code{op: opload, v: v})
+ if key = kv.Key; key != "" {
+ if key[0] == '$' {
key, name = key[1:], key
}
- c.append(&code{op: oppush, v: key})
} else if kv.KeyString != nil {
- c.append(&code{op: opload, v: v})
- if err := c.compileString(kv.KeyString, nil); err != nil {
- return nil, err
+ if key = kv.KeyString.Str; key == "" {
+ if err := c.compileString(kv.KeyString, nil); err != nil {
+ return nil, err
+ }
}
} else if kv.KeyQuery != nil {
- c.append(&code{op: opload, v: v})
if err := c.compileQuery(kv.KeyQuery); err != nil {
return nil, err
}
}
- c.append(&code{op: opload, v: v})
- c.append(&code{op: opload, v: v})
- // ref: compileCall
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+ if key != "" {
+ c.append(&code{op: opindex, v: key})
+ } else {
+ c.append(&code{op: opload, v: v})
+ c.append(&code{op: oppush, v: nil})
+ // ref: compileCall
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["_index"].callback, 2, "_index"}})
+ }
if name != "" {
if kv.Val != nil {
c.append(&code{op: opdup})
}
- ns, err := c.compilePattern(&Pattern{Name: name})
- if err != nil {
+ if vs, err = c.compilePattern(vs, &Pattern{Name: name}); err != nil {
return nil, err
}
- vs = append(vs, ns...)
}
if kv.Val != nil {
- ns, err := c.compilePattern(kv.Val)
- if err != nil {
+ if vs, err = c.compilePattern(vs, kv.Val); err != nil {
return nil, err
}
- vs = append(vs, ns...)
}
}
return vs, nil
@@ -650,17 +664,17 @@ func (c *compiler) compileIf(e *If) error {
}
pcc := len(c.codes)
setjumpifnot := c.lazy(func() *code {
- return &code{op: opjumpifnot, v: c.pc() + 1} // if falsy, skip then clause
+ return &code{op: opjumpifnot, v: len(c.codes)} // skip then clause
})
f = c.newScopeDepth()
if err := c.compileQuery(e.Then); err != nil {
return err
}
f()
- setjumpifnot()
defer c.lazy(func() *code {
- return &code{op: opjump, v: c.pc()} // jump to ret after else clause
+ return &code{op: opjump, v: len(c.codes)}
})()
+ setjumpifnot()
if len(e.Elif) > 0 {
return c.compileIf(&If{e.Elif[0].Cond, e.Elif[0].Then, e.Elif[1:], e.Else})
}
@@ -686,7 +700,7 @@ func (c *compiler) compileIf(e *If) error {
func (c *compiler) compileTry(e *Try) error {
c.appendCodeInfo(e)
setforktrybegin := c.lazy(func() *code {
- return &code{op: opforktrybegin, v: c.pc()}
+ return &code{op: opforktrybegin, v: len(c.codes)}
})
f := c.newScopeDepth()
if err := c.compileQuery(e.Body); err != nil {
@@ -695,7 +709,7 @@ func (c *compiler) compileTry(e *Try) error {
f()
c.append(&code{op: opforktryend})
defer c.lazy(func() *code {
- return &code{op: opjump, v: c.pc()}
+ return &code{op: opjump, v: len(c.codes)}
})()
setforktrybegin()
if e.Catch != nil {
@@ -709,9 +723,9 @@ func (c *compiler) compileTry(e *Try) error {
func (c *compiler) compileReduce(e *Reduce) error {
c.appendCodeInfo(e)
defer c.newScopeDepth()()
- defer c.lazy(func() *code {
- return &code{op: opfork, v: c.pc() - 2}
- })()
+ setfork := c.lazy(func() *code {
+ return &code{op: opfork, v: len(c.codes)}
+ })
c.append(&code{op: opdup})
v := c.newVariable()
f := c.newScopeDepth()
@@ -723,7 +737,7 @@ func (c *compiler) compileReduce(e *Reduce) error {
if err := c.compileTerm(e.Term); err != nil {
return err
}
- if _, err := c.compilePattern(e.Pattern); err != nil {
+ if _, err := c.compilePattern(nil, e.Pattern); err != nil {
return err
}
c.append(&code{op: opload, v: v})
@@ -734,6 +748,7 @@ func (c *compiler) compileReduce(e *Reduce) error {
f()
c.append(&code{op: opstore, v: v})
c.append(&code{op: opbacktrack})
+ setfork()
c.append(&code{op: oppop})
c.append(&code{op: opload, v: v})
return nil
@@ -753,7 +768,7 @@ func (c *compiler) compileForeach(e *Foreach) error {
if err := c.compileTerm(e.Term); err != nil {
return err
}
- if _, err := c.compilePattern(e.Pattern); err != nil {
+ if _, err := c.compilePattern(nil, e.Pattern); err != nil {
return err
}
c.append(&code{op: opload, v: v})
@@ -774,9 +789,7 @@ func (c *compiler) compileForeach(e *Foreach) error {
func (c *compiler) compileLabel(e *Label) error {
c.appendCodeInfo(e)
v := c.pushVariable("$%" + e.Ident[1:])
- defer c.lazy(func() *code {
- return &code{op: opforklabel, v: v}
- })()
+ c.append(&code{op: opforklabel, v: v})
return c.compileQuery(e.Body)
}
@@ -787,21 +800,21 @@ func (c *compiler) compileBreak(label string) error {
}
c.append(&code{op: oppop})
c.append(&code{op: opload, v: v})
- c.append(&code{op: opcall, v: [3]interface{}{
- func(v interface{}, _ []interface{}) interface{} {
- return &breakError{label, v}
- },
- 0,
- "_break",
- }})
+ c.append(&code{op: opcall, v: [3]any{funcBreak(label), 0, "_break"}})
return nil
}
+func funcBreak(label string) func(any, []any) any {
+ return func(v any, _ []any) any {
+ return &breakError{label, v}
+ }
+}
+
func (c *compiler) compileTerm(e *Term) error {
if len(e.SuffixList) > 0 {
s := e.SuffixList[len(e.SuffixList)-1]
t := *e // clone without changing e
- (&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1]
+ t.SuffixList = t.SuffixList[:len(e.SuffixList)-1]
return c.compileTermSuffix(&t, s)
}
switch e.Type {
@@ -827,11 +840,7 @@ func (c *compiler) compileTerm(e *Term) error {
case TermTypeArray:
return c.compileArray(e.Array)
case TermTypeNumber:
- v := normalizeNumber(json.Number(e.Number))
- if err, ok := v.(error); ok {
- return err
- }
- c.append(&code{op: opconst, v: v})
+ c.append(&code{op: opconst, v: toNumber(e.Number)})
return nil
case TermTypeUnary:
return c.compileUnary(e.Unary)
@@ -860,10 +869,15 @@ func (c *compiler) compileTerm(e *Term) error {
}
func (c *compiler) compileIndex(e *Term, x *Index) error {
- c.appendCodeInfo(x)
- if x.Name != "" {
- return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: &String{Str: x.Name}}}})
+ if k := x.toIndexKey(); k != nil {
+ if err := c.compileTerm(e); err != nil {
+ return err
+ }
+ c.appendCodeInfo(x)
+ c.append(&code{op: opindex, v: k})
+ return nil
}
+ c.appendCodeInfo(x)
if x.Str != nil {
return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: x.Str}}})
}
@@ -880,12 +894,11 @@ func (c *compiler) compileIndex(e *Term, x *Index) error {
}
func (c *compiler) compileFunc(e *Func) error {
- name := e.Name
if len(e.Args) == 0 {
- if f, v := c.lookupFuncOrVariable(name); f != nil {
+ if f, v := c.lookupFuncOrVariable(e.Name); f != nil {
return c.compileCallPc(f, e.Args)
} else if v != nil {
- if name[0] == '$' {
+ if e.Name[0] == '$' {
c.append(&code{op: oppop})
c.append(&code{op: opload, v: v.index})
} else {
@@ -893,8 +906,8 @@ func (c *compiler) compileFunc(e *Func) error {
c.append(&code{op: opcallpc})
}
return nil
- } else if name == "$ENV" || name == "env" {
- env := make(map[string]interface{})
+ } else if e.Name == "$ENV" || e.Name == "env" {
+ env := make(map[string]any)
if c.environLoader != nil {
for _, kv := range c.environLoader() {
if i := strings.IndexByte(kv, '='); i > 0 {
@@ -904,36 +917,42 @@ func (c *compiler) compileFunc(e *Func) error {
}
c.append(&code{op: opconst, v: env})
return nil
- } else if name[0] == '$' {
- return &variableNotFoundError{name}
+ } else if e.Name[0] == '$' {
+ return &variableNotFoundError{e.Name}
}
} else {
for i := len(c.scopes) - 1; i >= 0; i-- {
s := c.scopes[i]
for j := len(s.funcs) - 1; j >= 0; j-- {
- if f := s.funcs[j]; f.name == name && f.argcnt == len(e.Args) {
+ if f := s.funcs[j]; f.name == e.Name && f.argcnt == len(e.Args) {
return c.compileCallPc(f, e.Args)
}
}
}
}
- if name[0] == '_' {
- name = name[1:]
+ if f := c.lookupBuiltin(e.Name, len(e.Args)); f != nil {
+ return c.compileCallPc(f, e.Args)
}
- if fds, ok := builtinFuncDefs[name]; ok {
+ if fds, ok := builtinFuncDefs[e.Name]; ok {
for _, fd := range fds {
if len(fd.Args) == len(e.Args) {
if err := c.compileFuncDef(fd, true); err != nil {
return err
}
+ break
}
}
- s := c.scopes[0]
- for i := len(s.funcs) - 1; i >= 0; i-- {
- if f := s.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) {
- return c.compileCallPc(f, e.Args)
+ if len(fds) == 0 {
+ switch e.Name {
+ case "_assign":
+ c.compileAssign()
+ case "_modify":
+ c.compileModify()
}
}
+ if f := c.lookupBuiltin(e.Name, len(e.Args)); f != nil {
+ return c.compileCallPc(f, e.Args)
+ }
}
if fn, ok := internalFuncs[e.Name]; ok && fn.accept(len(e.Args)) {
switch e.Name {
@@ -949,27 +968,27 @@ func (c *compiler) compileFunc(e *Func) error {
return nil
case "builtins":
return c.compileCallInternal(
- [3]interface{}{c.funcBuiltins, 0, e.Name},
+ [3]any{c.funcBuiltins, 0, e.Name},
e.Args,
true,
- false,
+ -1,
)
case "input":
if c.inputIter == nil {
return &inputNotAllowedError{}
}
return c.compileCallInternal(
- [3]interface{}{c.funcInput, 0, e.Name},
+ [3]any{c.funcInput, 0, e.Name},
e.Args,
true,
- false,
+ -1,
)
case "modulemeta":
return c.compileCallInternal(
- [3]interface{}{c.funcModulemeta, 0, e.Name},
+ [3]any{c.funcModulemeta, 0, e.Name},
e.Args,
true,
- false,
+ -1,
)
default:
return c.compileCall(e.Name, e.Args)
@@ -977,22 +996,130 @@ func (c *compiler) compileFunc(e *Func) error {
}
if fn, ok := c.customFuncs[e.Name]; ok && fn.accept(len(e.Args)) {
if err := c.compileCallInternal(
- [3]interface{}{fn.callback, len(e.Args), e.Name},
+ [3]any{fn.callback, len(e.Args), e.Name},
e.Args,
true,
- false,
+ -1,
); err != nil {
return err
}
if fn.iter {
- c.append(&code{op: opeach})
+ c.append(&code{op: opiter})
}
return nil
}
return &funcNotFoundError{e}
}
-func (c *compiler) funcBuiltins(interface{}, []interface{}) interface{} {
+// Appends the compiled code for the assignment operator (`=`) to maximize
+// performance. Originally the operator was implemented as follows.
+//
+// def _assign(p; $x): reduce path(p) as $q (.; setpath($q; $x));
+//
+// To overcome the difficulty of reducing allocations on `setpath`, we use the
+// `allocator` type and track the allocated addresses during the reduction.
+func (c *compiler) compileAssign() {
+ defer c.appendBuiltin("_assign", 2)()
+ scope := c.newScope()
+ v, p := [2]int{scope.id, 0}, [2]int{scope.id, 1}
+ x, a := [2]int{scope.id, 2}, [2]int{scope.id, 3}
+ // Cannot reuse v, p due to backtracking in x.
+ w, q := [2]int{scope.id, 4}, [2]int{scope.id, 5}
+ c.appends(
+ &code{op: opscope, v: [3]int{scope.id, 6, 2}},
+ &code{op: opstore, v: v}, // def _assign(p; $x):
+ &code{op: opstore, v: p},
+ &code{op: opstore, v: x},
+ &code{op: opload, v: v},
+ &code{op: opexpbegin},
+ &code{op: opload, v: x},
+ &code{op: opcallpc},
+ &code{op: opstore, v: x},
+ &code{op: opexpend},
+ &code{op: oppush, v: nil},
+ &code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
+ &code{op: opstore, v: a},
+ &code{op: opload, v: v},
+ &code{op: opfork, v: len(c.codes) + 30}, // reduce [L1]
+ &code{op: opdup},
+ &code{op: opstore, v: w},
+ &code{op: oppathbegin}, // path(p)
+ &code{op: opload, v: p},
+ &code{op: opcallpc},
+ &code{op: opload, v: w},
+ &code{op: oppathend},
+ &code{op: opstore, v: q}, // as $q (.;
+ &code{op: opload, v: a}, // setpath($q; $x)
+ &code{op: opload, v: x},
+ &code{op: opload, v: q},
+ &code{op: opload, v: w},
+ &code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
+ &code{op: opstore, v: w},
+ &code{op: opbacktrack}, // );
+ &code{op: oppop}, // [L1]
+ &code{op: opload, v: w},
+ &code{op: opret},
+ )
+}
+
+// Appends the compiled code for the update-assignment operator (`|=`) to
+// maximize performance. We use the `allocator` type, just like `_assign/2`.
+func (c *compiler) compileModify() {
+ defer c.appendBuiltin("_modify", 2)()
+ scope := c.newScope()
+ v, p := [2]int{scope.id, 0}, [2]int{scope.id, 1}
+ f, d := [2]int{scope.id, 2}, [2]int{scope.id, 3}
+ a, l := [2]int{scope.id, 4}, [2]int{scope.id, 5}
+ c.appends(
+ &code{op: opscope, v: [3]int{scope.id, 6, 2}},
+ &code{op: opstore, v: v}, // def _modify(p; f):
+ &code{op: opstore, v: p},
+ &code{op: opstore, v: f},
+ &code{op: oppush, v: []any{}},
+ &code{op: opstore, v: d},
+ &code{op: oppush, v: nil},
+ &code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
+ &code{op: opstore, v: a},
+ &code{op: opload, v: v},
+ &code{op: opfork, v: len(c.codes) + 39}, // reduce [L1]
+ &code{op: oppathbegin}, // path(p)
+ &code{op: opload, v: p},
+ &code{op: opcallpc},
+ &code{op: opload, v: v},
+ &code{op: oppathend},
+ &code{op: opstore, v: p}, // as $p (.;
+ &code{op: opforklabel, v: l}, // label $l |
+ &code{op: opload, v: v}, //
+ &code{op: opfork, v: len(c.codes) + 36}, // [L2]
+ &code{op: oppop}, // (getpath($p) |
+ &code{op: opload, v: a},
+ &code{op: opload, v: p},
+ &code{op: opload, v: v},
+ &code{op: opcall, v: [3]any{internalFuncs["getpath"].callback, 1, "getpath"}},
+ &code{op: opload, v: f}, // f)
+ &code{op: opcallpc},
+ &code{op: opload, v: p}, // setpath($p; ...)
+ &code{op: opload, v: v},
+ &code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
+ &code{op: opstore, v: v},
+ &code{op: opload, v: v}, // ., break $l
+ &code{op: opfork, v: len(c.codes) + 34}, // [L4]
+ &code{op: opjump, v: len(c.codes) + 38}, // [L3]
+ &code{op: opload, v: l}, // [L4]
+ &code{op: opcall, v: [3]any{funcBreak(""), 0, "_break"}},
+ &code{op: opload, v: p}, // append $p to $d [L2]
+ &code{op: opappend, v: d}, //
+ &code{op: opbacktrack}, // ) | [L3]
+ &code{op: oppop}, // delpaths($d); [L1]
+ &code{op: opload, v: a},
+ &code{op: opload, v: d},
+ &code{op: opload, v: v},
+ &code{op: opcall, v: [3]any{funcDelpathsWithAllocator, 2, "_delpaths"}},
+ &code{op: opret},
+ )
+}
+
+func (c *compiler) funcBuiltins(any, []any) any {
type funcNameArity struct {
name string
arity int
@@ -1027,14 +1154,14 @@ func (c *compiler) funcBuiltins(interface{}, []interface{}) interface{} {
return xs[i].name < xs[j].name ||
xs[i].name == xs[j].name && xs[i].arity < xs[j].arity
})
- ys := make([]interface{}, len(xs))
+ ys := make([]any, len(xs))
for i, x := range xs {
ys[i] = x.name + "/" + strconv.Itoa(x.arity)
}
return ys
}
-func (c *compiler) funcInput(interface{}, []interface{}) interface{} {
+func (c *compiler) funcInput(any, []any) any {
v, ok := c.inputIter.Next()
if !ok {
return errors.New("break")
@@ -1042,7 +1169,7 @@ func (c *compiler) funcInput(interface{}, []interface{}) interface{} {
return normalizeNumbers(v)
}
-func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
+func (c *compiler) funcModulemeta(v any, _ []any) any {
s, ok := v.(string)
if !ok {
return &funcTypeError{"modulemeta", v}
@@ -1053,7 +1180,7 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
var q *Query
var err error
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
+ LoadModuleWithMeta(string, map[string]any) (*Query, error)
}); ok {
if q, err = moduleLoader.LoadModuleWithMeta(s, nil); err != nil {
return err
@@ -1067,13 +1194,13 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
}
meta := q.Meta.ToValue()
if meta == nil {
- meta = make(map[string]interface{})
+ meta = make(map[string]any)
}
- var deps []interface{}
+ var deps []any
for _, i := range q.Imports {
v := i.Meta.ToValue()
if v == nil {
- v = make(map[string]interface{})
+ v = make(map[string]any)
} else {
for k := range v {
// dirty hack to remove the internal fields
@@ -1103,7 +1230,7 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
func (c *compiler) compileObject(e *Object) error {
c.appendCodeInfo(e)
if len(e.KeyVals) == 0 {
- c.append(&code{op: opconst, v: map[string]interface{}{}})
+ c.append(&code{op: opconst, v: map[string]any{}})
return nil
}
defer c.newScopeDepth()()
@@ -1128,7 +1255,7 @@ func (c *compiler) compileObject(e *Object) error {
return nil
}
}
- w := make(map[string]interface{}, l)
+ w := make(map[string]any, l)
for i := 0; i < l; i++ {
w[c.codes[pc+i*3].v.(string)] = c.codes[pc+i*3+2].v
}
@@ -1138,61 +1265,57 @@ func (c *compiler) compileObject(e *Object) error {
}
func (c *compiler) compileObjectKeyVal(v [2]int, kv *ObjectKeyVal) error {
- if kv.KeyOnly != "" {
- if kv.KeyOnly[0] == '$' {
- c.append(&code{op: oppush, v: kv.KeyOnly[1:]})
- c.append(&code{op: opload, v: v})
- return c.compileFunc(&Func{Name: kv.KeyOnly})
- }
- c.append(&code{op: oppush, v: kv.KeyOnly})
- c.append(&code{op: opload, v: v})
- return c.compileIndex(&Term{Type: TermTypeIdentity}, &Index{Name: kv.KeyOnly})
- } else if kv.KeyOnlyString != nil {
- c.append(&code{op: opload, v: v})
- if err := c.compileString(kv.KeyOnlyString, nil); err != nil {
- return err
- }
- c.append(&code{op: opdup})
- c.append(&code{op: opload, v: v})
- c.append(&code{op: opload, v: v})
- // ref: compileCall
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
- return nil
- } else {
- if kv.KeyQuery != nil {
- c.append(&code{op: opload, v: v})
- f := c.newScopeDepth()
- if err := c.compileQuery(kv.KeyQuery); err != nil {
- return err
+ if key := kv.Key; key != "" {
+ if key[0] == '$' {
+ if kv.Val == nil { // {$foo} == {foo:$foo}
+ c.append(&code{op: oppush, v: key[1:]})
}
- f()
- } else if kv.KeyString != nil {
c.append(&code{op: opload, v: v})
- if err := c.compileString(kv.KeyString, nil); err != nil {
+ if err := c.compileFunc(&Func{Name: key}); err != nil {
return err
}
- if d := c.codes[len(c.codes)-1]; d.op == opconst {
- c.codes[len(c.codes)-2] = &code{op: oppush, v: d.v}
- c.codes = c.codes[:len(c.codes)-1]
+ } else {
+ c.append(&code{op: oppush, v: key})
+ if kv.Val == nil { // {foo} == {foo:.foo}
+ c.append(&code{op: opload, v: v})
+ c.append(&code{op: opindex, v: key})
}
- } else if kv.Key[0] == '$' {
+ }
+ } else if key := kv.KeyString; key != nil {
+ if key.Queries == nil {
+ c.append(&code{op: oppush, v: key.Str})
+ if kv.Val == nil { // {"foo"} == {"foo":.["foo"]}
+ c.append(&code{op: opload, v: v})
+ c.append(&code{op: opindex, v: key.Str})
+ }
+ } else {
c.append(&code{op: opload, v: v})
- if err := c.compileFunc(&Func{Name: kv.Key}); err != nil {
+ if err := c.compileString(key, nil); err != nil {
return err
}
- } else {
- c.append(&code{op: oppush, v: kv.Key})
+ if kv.Val == nil {
+ c.append(&code{op: opdup})
+ c.append(&code{op: opload, v: v})
+ c.append(&code{op: oppush, v: nil})
+ // ref: compileCall
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["_index"].callback, 2, "_index"}})
+ }
}
+ } else if kv.KeyQuery != nil {
c.append(&code{op: opload, v: v})
- return c.compileObjectVal(kv.Val)
- }
-}
-
-func (c *compiler) compileObjectVal(e *ObjectVal) error {
- for _, e := range e.Queries {
- if err := c.compileQuery(e); err != nil {
+ f := c.newScopeDepth()
+ if err := c.compileQuery(kv.KeyQuery); err != nil {
return err
}
+ f()
+ }
+ if kv.Val != nil {
+ c.append(&code{op: opload, v: v})
+ for _, e := range kv.Val.Queries {
+ if err := c.compileQuery(e); err != nil {
+ return err
+ }
+ }
}
return nil
}
@@ -1200,25 +1323,23 @@ func (c *compiler) compileObjectVal(e *ObjectVal) error {
func (c *compiler) compileArray(e *Array) error {
c.appendCodeInfo(e)
if e.Query == nil {
- c.append(&code{op: opconst, v: []interface{}{}})
+ c.append(&code{op: opconst, v: []any{}})
return nil
}
- c.append(&code{op: oppush, v: []interface{}{}})
+ c.append(&code{op: oppush, v: []any{}})
arr := c.newVariable()
c.append(&code{op: opstore, v: arr})
pc := len(c.codes)
- c.append(&code{op: opfork})
- defer func() {
- if pc < len(c.codes) {
- c.codes[pc].v = c.pc() - 2
- }
- }()
+ setfork := c.lazy(func() *code {
+ return &code{op: opfork, v: len(c.codes)}
+ })
defer c.newScopeDepth()()
if err := c.compileQuery(e.Query); err != nil {
return err
}
c.append(&code{op: opappend, v: arr})
c.append(&code{op: opbacktrack})
+ setfork()
c.append(&code{op: oppop})
c.append(&code{op: opload, v: arr})
if e.Query.Op == OpPipe {
@@ -1236,7 +1357,7 @@ func (c *compiler) compileArray(e *Array) error {
return nil
}
}
- v := make([]interface{}, l)
+ v := make([]any, l)
for i := 0; i < l; i++ {
v[i] = c.codes[pc+i*2+l].v
}
@@ -1247,6 +1368,10 @@ func (c *compiler) compileArray(e *Array) error {
func (c *compiler) compileUnary(e *Unary) error {
c.appendCodeInfo(e)
+ if v := e.toNumber(); v != nil {
+ c.append(&code{op: opconst, v: v})
+ return nil
+ }
if err := c.compileTerm(e.Term); err != nil {
return err
}
@@ -1260,12 +1385,12 @@ func (c *compiler) compileUnary(e *Unary) error {
}
}
-func (c *compiler) compileFormat(fmt string, str *String) error {
- f := formatToFunc(fmt)
+func (c *compiler) compileFormat(format string, str *String) error {
+ f := formatToFunc(format)
if f == nil {
f = &Func{
Name: "format",
- Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: fmt[1:]}}}},
+ Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: format[1:]}}}},
}
}
if str == nil {
@@ -1274,8 +1399,8 @@ func (c *compiler) compileFormat(fmt string, str *String) error {
return c.compileString(str, f)
}
-func formatToFunc(fmt string) *Func {
- switch fmt {
+func formatToFunc(format string) *Func {
+ switch format {
case "@text":
return &Func{Name: "tostring"}
case "@json":
@@ -1328,14 +1453,14 @@ func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error {
if err := c.compileTerm(e); err != nil {
return err
}
- c.append(&code{op: opeach})
+ c.append(&code{op: opiter})
return nil
} else if s.Optional {
if len(e.SuffixList) > 0 {
- if u, ok := e.SuffixList[len(e.SuffixList)-1].toTerm(); ok {
- t := *e // clone without changing e
- (&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1]
- if err := c.compileTerm(&t); err != nil {
+ if u := e.SuffixList[len(e.SuffixList)-1].toTerm(); u != nil {
+ // no need to clone (ref: compileTerm)
+ e.SuffixList = e.SuffixList[:len(e.SuffixList)-1]
+ if err := c.compileTerm(e); err != nil {
return err
}
e = u
@@ -1343,12 +1468,7 @@ func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error {
}
return c.compileTry(&Try{Body: &Query{Term: e}})
} else if s.Bind != nil {
- c.append(&code{op: opdup})
- c.append(&code{op: opexpbegin})
- if err := c.compileTerm(e); err != nil {
- return err
- }
- return c.compileBind(s.Bind)
+ return c.compileBind(e, s.Bind)
} else {
return fmt.Errorf("invalid suffix: %s", s)
}
@@ -1356,46 +1476,56 @@ func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error {
func (c *compiler) compileCall(name string, args []*Query) error {
fn := internalFuncs[name]
+ var indexing int
+ switch name {
+ case "_index", "_slice":
+ indexing = 1
+ case "getpath":
+ indexing = 0
+ default:
+ indexing = -1
+ }
if err := c.compileCallInternal(
- [3]interface{}{fn.callback, len(args), name},
+ [3]any{fn.callback, len(args), name},
args,
true,
- name == "_index" || name == "_slice",
+ indexing,
); err != nil {
return err
}
if fn.iter {
- c.append(&code{op: opeach})
+ c.append(&code{op: opiter})
}
return nil
}
func (c *compiler) compileCallPc(fn *funcinfo, args []*Query) error {
- return c.compileCallInternal(fn.pc, args, false, false)
+ return c.compileCallInternal(fn.pc, args, false, -1)
}
func (c *compiler) compileCallInternal(
- fn interface{}, args []*Query, internal, indexing bool) error {
+ fn any, args []*Query, internal bool, indexing int,
+) error {
if len(args) == 0 {
c.append(&code{op: opcall, v: fn})
return nil
}
- idx := c.newVariable()
- c.append(&code{op: opstore, v: idx})
- if indexing && len(args) > 1 {
+ v := c.newVariable()
+ c.append(&code{op: opstore, v: v})
+ if indexing >= 0 {
c.append(&code{op: opexpbegin})
}
for i := len(args) - 1; i >= 0; i-- {
- pc := c.pc() + 1 // skip opjump (ref: compileFuncDef)
+ pc := len(c.codes) + 1 // skip opjump (ref: compileFuncDef)
name := "lambda:" + strconv.Itoa(pc)
if err := c.compileFuncDef(&FuncDef{Name: name, Body: args[i]}, false); err != nil {
return err
}
if internal {
- switch c.pc() - pc {
+ switch len(c.codes) - pc {
case 2: // optimize identity argument (opscope, opret)
j := len(c.codes) - 3
- c.codes[j] = &code{op: opload, v: idx}
+ c.codes[j] = &code{op: opload, v: v}
c.codes = c.codes[:j+1]
s := c.scopes[len(c.scopes)-1]
s.funcs = s.funcs[:len(s.funcs)-1]
@@ -1406,7 +1536,7 @@ func (c *compiler) compileCallInternal(
c.codes[j] = &code{op: oppush, v: c.codes[j+2].v}
c.codes = c.codes[:j+1]
} else {
- c.codes[j] = &code{op: opload, v: idx}
+ c.codes[j] = &code{op: opload, v: v}
c.codes[j+1] = c.codes[j+2]
c.codes = c.codes[:j+2]
}
@@ -1414,14 +1544,14 @@ func (c *compiler) compileCallInternal(
s.funcs = s.funcs[:len(s.funcs)-1]
c.deleteCodeInfo(name)
default:
- c.append(&code{op: opload, v: idx})
+ c.append(&code{op: opload, v: v})
c.append(&code{op: oppushpc, v: pc})
c.append(&code{op: opcallpc})
}
} else {
c.append(&code{op: oppushpc, v: pc})
}
- if indexing && i == 1 {
+ if i == indexing {
if c.codes[len(c.codes)-2].op == opexpbegin {
c.codes[len(c.codes)-2] = c.codes[len(c.codes)-1]
c.codes = c.codes[:len(c.codes)-1]
@@ -1430,7 +1560,11 @@ func (c *compiler) compileCallInternal(
}
}
}
- c.append(&code{op: opload, v: idx})
+ if indexing > 0 {
+ c.append(&code{op: oppush, v: nil})
+ } else {
+ c.append(&code{op: opload, v: v})
+ }
c.append(&code{op: opcall, v: fn})
return nil
}
@@ -1439,8 +1573,8 @@ func (c *compiler) append(code *code) {
c.codes = append(c.codes, code)
}
-func (c *compiler) pc() int {
- return len(c.codes)
+func (c *compiler) appends(codes ...*code) {
+ c.codes = append(c.codes, codes...)
}
func (c *compiler) lazy(f func() *code) func() {
diff --git a/vendor/github.com/itchyny/gojq/debug.go b/vendor/github.com/itchyny/gojq/debug.go
index 4a346fb2..ad3d7216 100644
--- a/vendor/github.com/itchyny/gojq/debug.go
+++ b/vendor/github.com/itchyny/gojq/debug.go
@@ -1,5 +1,5 @@
-//go:build debug
-// +build debug
+//go:build gojq_debug
+// +build gojq_debug
package gojq
@@ -32,7 +32,7 @@ type codeinfo struct {
pc int
}
-func (c *compiler) appendCodeInfo(x interface{}) {
+func (c *compiler) appendCodeInfo(x any) {
if !debug {
return
}
@@ -47,7 +47,7 @@ func (c *compiler) appendCodeInfo(x interface{}) {
if c.codes[len(c.codes)-1] != nil && c.codes[len(c.codes)-1].op == opret && strings.HasPrefix(name, "end of ") {
diff = -1
}
- c.codeinfos = append(c.codeinfos, codeinfo{name, c.pc() + diff})
+ c.codeinfos = append(c.codeinfos, codeinfo{name, len(c.codes) + diff})
}
func (c *compiler) deleteCodeInfo(name string) {
@@ -182,7 +182,7 @@ func debugOperand(c *code) string {
switch v := c.v.(type) {
case int:
return strconv.Itoa(v)
- case [3]interface{}:
+ case [3]any:
return fmt.Sprintf("%s/%d", v[2], v[1])
default:
panic(c)
@@ -192,17 +192,21 @@ func debugOperand(c *code) string {
}
}
-func debugValue(v interface{}) string {
+func debugValue(v any) string {
switch v := v.(type) {
case Iter:
return fmt.Sprintf("gojq.Iter(%#v)", v)
+ case []pathValue:
+ return fmt.Sprintf("[]gojq.pathValue(%v)", v)
case [2]int:
return fmt.Sprintf("[%d,%d]", v[0], v[1])
case [3]int:
return fmt.Sprintf("[%d,%d,%d]", v[0], v[1], v[2])
- case [3]interface{}:
+ case [3]any:
return fmt.Sprintf("[%v,%v,%v]", v[0], v[1], v[2])
+ case allocator:
+ return fmt.Sprintf("%v", v)
default:
- return previewValue(v)
+ return Preview(v)
}
}
diff --git a/vendor/github.com/itchyny/gojq/deepequal.go b/vendor/github.com/itchyny/gojq/deepequal.go
deleted file mode 100644
index 37c56e42..00000000
--- a/vendor/github.com/itchyny/gojq/deepequal.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package gojq
-
-import (
- "math"
- "math/big"
-)
-
-func deepEqual(l, r interface{}) bool {
- return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
- return l == r
- },
- func(l, r float64) interface{} {
- return l == r || math.IsNaN(l) && math.IsNaN(r)
- },
- func(l, r *big.Int) interface{} {
- return l.Cmp(r) == 0
- },
- func(l, r string) interface{} {
- return l == r
- },
- func(l, r []interface{}) interface{} {
- if len(l) != len(r) {
- return false
- }
- for i, v := range l {
- if !deepEqual(v, r[i]) {
- return false
- }
- }
- return true
- },
- func(l, r map[string]interface{}) interface{} {
- if len(l) != len(r) {
- return false
- }
- for k, v := range l {
- if !deepEqual(v, r[k]) {
- return false
- }
- }
- return true
- },
- func(l, r interface{}) interface{} {
- return l == r
- },
- ).(bool)
-}
diff --git a/vendor/github.com/itchyny/gojq/encoder.go b/vendor/github.com/itchyny/gojq/encoder.go
index c7905f96..3233e8a9 100644
--- a/vendor/github.com/itchyny/gojq/encoder.go
+++ b/vendor/github.com/itchyny/gojq/encoder.go
@@ -14,25 +14,29 @@ import (
// Marshal returns the jq-flavored JSON encoding of v.
//
-// This method only accepts limited types (nil, bool, int, float64, *big.Int,
-// string, []interface{} and map[string]interface{}) because these are the
-// possible types a gojq iterator can emit. This method marshals NaN to null,
-// truncates infinities to (+|-) math.MaxFloat64, uses \b and \f in strings,
-// and does not escape '<' and '>' for embedding in HTML. These behaviors are
-// based on the marshaler of jq command and different from Go standard library
-// method json.Marshal.
-func Marshal(v interface{}) ([]byte, error) {
+// This method accepts only limited types (nil, bool, int, float64, *big.Int,
+// string, []any, and map[string]any) because these are the possible types a
+// gojq iterator can emit. This method marshals NaN to null, truncates
+// infinities to (+|-) math.MaxFloat64, uses \b and \f in strings, and does not
+// escape '<', '>', '&', '\u2028', and '\u2029'. These behaviors are based on
+// the marshaler of jq command, and different from json.Marshal in the Go
+// standard library. Note that the result is not safe to embed in HTML.
+func Marshal(v any) ([]byte, error) {
var b bytes.Buffer
(&encoder{w: &b}).encode(v)
return b.Bytes(), nil
}
-func jsonMarshal(v interface{}) string {
+func jsonMarshal(v any) string {
var sb strings.Builder
(&encoder{w: &sb}).encode(v)
return sb.String()
}
+func jsonEncodeString(sb *strings.Builder, v string) {
+ (&encoder{w: sb}).encodeString(v)
+}
+
type encoder struct {
w interface {
io.Writer
@@ -42,7 +46,7 @@ type encoder struct {
buf [64]byte
}
-func (e *encoder) encode(v interface{}) {
+func (e *encoder) encode(v any) {
switch v := v.(type) {
case nil:
e.w.WriteString("null")
@@ -60,12 +64,12 @@ func (e *encoder) encode(v interface{}) {
e.w.Write(v.Append(e.buf[:0], 10))
case string:
e.encodeString(v)
- case []interface{}:
+ case []any:
e.encodeArray(v)
- case map[string]interface{}:
- e.encodeMap(v)
+ case map[string]any:
+ e.encodeObject(v)
default:
- panic(fmt.Sprintf("invalid value: %v", v))
+ panic(fmt.Sprintf("invalid type: %[1]T (%[1]v)", v))
}
}
@@ -80,12 +84,12 @@ func (e *encoder) encodeFloat64(f float64) {
} else if f <= -math.MaxFloat64 {
f = -math.MaxFloat64
}
- fmt := byte('f')
+ format := byte('f')
if x := math.Abs(f); x != 0 && x < 1e-6 || x >= 1e21 {
- fmt = 'e'
+ format = 'e'
}
- buf := strconv.AppendFloat(e.buf[:0], f, fmt, -1, 64)
- if fmt == 'e' {
+ buf := strconv.AppendFloat(e.buf[:0], f, format, -1, 64)
+ if format == 'e' {
// clean up e-09 to e-9
if n := len(buf); n >= 4 && buf[n-4] == 'e' && buf[n-3] == '-' && buf[n-2] == '0' {
buf[n-2] = buf[n-1]
@@ -101,30 +105,31 @@ func (e *encoder) encodeString(s string) {
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if ']' <= b && b <= '~' || '#' <= b && b <= '[' || b == ' ' || b == '!' {
+ if ' ' <= b && b <= '~' && b != '"' && b != '\\' {
i++
continue
}
if start < i {
e.w.WriteString(s[start:i])
}
- e.w.WriteByte('\\')
switch b {
- case '\\', '"':
- e.w.WriteByte(b)
+ case '"':
+ e.w.WriteString(`\"`)
+ case '\\':
+ e.w.WriteString(`\\`)
case '\b':
- e.w.WriteByte('b')
+ e.w.WriteString(`\b`)
case '\f':
- e.w.WriteByte('f')
+ e.w.WriteString(`\f`)
case '\n':
- e.w.WriteByte('n')
+ e.w.WriteString(`\n`)
case '\r':
- e.w.WriteByte('r')
+ e.w.WriteString(`\r`)
case '\t':
- e.w.WriteByte('t')
+ e.w.WriteString(`\t`)
default:
const hex = "0123456789abcdef"
- e.w.WriteString("u00")
+ e.w.WriteString(`\u00`)
e.w.WriteByte(hex[b>>4])
e.w.WriteByte(hex[b&0xF])
}
@@ -150,7 +155,7 @@ func (e *encoder) encodeString(s string) {
e.w.WriteByte('"')
}
-func (e *encoder) encodeArray(vs []interface{}) {
+func (e *encoder) encodeArray(vs []any) {
e.w.WriteByte('[')
for i, v := range vs {
if i > 0 {
@@ -161,11 +166,11 @@ func (e *encoder) encodeArray(vs []interface{}) {
e.w.WriteByte(']')
}
-func (e *encoder) encodeMap(vs map[string]interface{}) {
+func (e *encoder) encodeObject(vs map[string]any) {
e.w.WriteByte('{')
type keyVal struct {
key string
- val interface{}
+ val any
}
kvs := make([]keyVal, len(vs))
var i int
diff --git a/vendor/github.com/itchyny/gojq/env.go b/vendor/github.com/itchyny/gojq/env.go
index dd1859c4..bf058eda 100644
--- a/vendor/github.com/itchyny/gojq/env.go
+++ b/vendor/github.com/itchyny/gojq/env.go
@@ -7,7 +7,7 @@ type env struct {
stack *stack
paths *stack
scopes *scopeStack
- values []interface{}
+ values []any
codes []*code
codeinfos []codeinfo
forks []fork
@@ -15,7 +15,7 @@ type env struct {
offset int
expdepth int
label int
- args [32]interface{} // len(env.args) > maxarity
+ args [32]any // len(env.args) > maxarity
ctx context.Context
}
diff --git a/vendor/github.com/itchyny/gojq/error.go b/vendor/github.com/itchyny/gojq/error.go
index c13e9777..695463f3 100644
--- a/vendor/github.com/itchyny/gojq/error.go
+++ b/vendor/github.com/itchyny/gojq/error.go
@@ -1,23 +1,18 @@
package gojq
-import (
- "fmt"
- "math/big"
- "strconv"
- "strings"
-)
+import "strconv"
// ValueError is an interface for errors with a value for internal function.
// Return an error implementing this interface when you want to catch error
// values (not error messages) by try-catch, just like built-in error function.
-// Refer to WithFunction to add a custom internal function.
+// Refer to [WithFunction] to add a custom internal function.
type ValueError interface {
error
- Value() interface{}
+ Value() any
}
type expectedObjectError struct {
- v interface{}
+ v any
}
func (err *expectedObjectError) Error() string {
@@ -25,7 +20,7 @@ func (err *expectedObjectError) Error() string {
}
type expectedArrayError struct {
- v interface{}
+ v any
}
func (err *expectedArrayError) Error() string {
@@ -33,7 +28,7 @@ func (err *expectedArrayError) Error() string {
}
type expectedStringError struct {
- v interface{}
+ v any
}
func (err *expectedStringError) Error() string {
@@ -41,7 +36,7 @@ func (err *expectedStringError) Error() string {
}
type iteratorError struct {
- v interface{}
+ v any
}
func (err *iteratorError) Error() string {
@@ -49,15 +44,15 @@ func (err *iteratorError) Error() string {
}
type arrayIndexTooLargeError struct {
- v interface{}
+ v any
}
func (err *arrayIndexTooLargeError) Error() string {
- return "array index too large: " + previewValue(err.v)
+ return "array index too large: " + Preview(err.v)
}
type objectKeyNotStringError struct {
- v interface{}
+ v any
}
func (err *objectKeyNotStringError) Error() string {
@@ -65,15 +60,23 @@ func (err *objectKeyNotStringError) Error() string {
}
type arrayIndexNotNumberError struct {
- v interface{}
+ v any
}
func (err *arrayIndexNotNumberError) Error() string {
return "expected a number for indexing an array but got: " + typeErrorPreview(err.v)
}
+type stringIndexNotNumberError struct {
+ v any
+}
+
+func (err *stringIndexNotNumberError) Error() string {
+ return "expected a number for indexing a string but got: " + typeErrorPreview(err.v)
+}
+
type expectedStartEndError struct {
- v interface{}
+ v any
}
func (err *expectedStartEndError) Error() string {
@@ -82,7 +85,7 @@ func (err *expectedStartEndError) Error() string {
type lengthMismatchError struct {
name string
- v, x []interface{}
+ v, x []any
}
func (err *lengthMismatchError) Error() string {
@@ -105,7 +108,7 @@ func (err *funcNotFoundError) Error() string {
type funcTypeError struct {
name string
- v interface{}
+ v any
}
func (err *funcTypeError) Error() string {
@@ -113,7 +116,7 @@ func (err *funcTypeError) Error() string {
}
type exitCodeError struct {
- value interface{}
+ value any
code int
halt bool
}
@@ -129,7 +132,7 @@ func (err *exitCodeError) IsEmptyError() bool {
return err.value == nil
}
-func (err *exitCodeError) Value() interface{} {
+func (err *exitCodeError) Value() any {
return err.value
}
@@ -141,25 +144,41 @@ func (err *exitCodeError) IsHaltError() bool {
return err.halt
}
-type funcContainsError struct {
- l, r interface{}
+type containsTypeError struct {
+ l, r any
}
-func (err *funcContainsError) Error() string {
- return "cannot check contains(" + previewValue(err.r) + "): " + typeErrorPreview(err.l)
+func (err *containsTypeError) Error() string {
+ return "cannot check contains(" + Preview(err.r) + "): " + typeErrorPreview(err.l)
}
type hasKeyTypeError struct {
- l, r interface{}
+ l, r any
}
func (err *hasKeyTypeError) Error() string {
return "cannot check whether " + typeErrorPreview(err.l) + " has a key: " + typeErrorPreview(err.r)
}
+type flattenDepthError struct {
+ v float64
+}
+
+func (err *flattenDepthError) Error() string {
+ return "flatten depth must not be negative: " + typeErrorPreview(err.v)
+}
+
+type joinTypeError struct {
+ v any
+}
+
+func (err *joinTypeError) Error() string {
+ return "cannot join: " + typeErrorPreview(err.v)
+}
+
type unaryTypeError struct {
name string
- v interface{}
+ v any
}
func (err *unaryTypeError) Error() string {
@@ -168,7 +187,7 @@ func (err *unaryTypeError) Error() string {
type binopTypeError struct {
name string
- l, r interface{}
+ l, r any
}
func (err *binopTypeError) Error() string {
@@ -176,7 +195,7 @@ func (err *binopTypeError) Error() string {
}
type zeroDivisionError struct {
- l, r interface{}
+ l, r any
}
func (err *zeroDivisionError) Error() string {
@@ -184,11 +203,11 @@ func (err *zeroDivisionError) Error() string {
}
type zeroModuloError struct {
- l, r interface{}
+ l, r any
}
func (err *zeroModuloError) Error() string {
- return "cannot modulo " + typeErrorPreview(err.l) + " by: " + typeErrorPreview(err.r) + ""
+ return "cannot modulo " + typeErrorPreview(err.l) + " by: " + typeErrorPreview(err.r)
}
type formatNotFoundError struct {
@@ -199,21 +218,13 @@ func (err *formatNotFoundError) Error() string {
return "format not defined: " + err.n
}
-type formatCsvTsvRowError struct {
+type formatRowError struct {
typ string
- v interface{}
+ v any
}
-func (err *formatCsvTsvRowError) Error() string {
- return "invalid " + err.typ + " row: " + typeErrorPreview(err.v)
-}
-
-type formatShError struct {
- v interface{}
-}
-
-func (err *formatShError) Error() string {
- return "cannot escape for shell: " + typeErrorPreview(err.v)
+func (err *formatRowError) Error() string {
+ return "@" + err.typ + " cannot format an array including: " + typeErrorPreview(err.v)
}
type tooManyVariableValuesError struct{}
@@ -248,7 +259,7 @@ func (err *variableNameError) Error() string {
type breakError struct {
n string
- v interface{}
+ v any
}
func (err *breakError) Error() string {
@@ -268,7 +279,7 @@ func (err *tryEndError) Error() string {
}
type invalidPathError struct {
- v interface{}
+ v any
}
func (err *invalidPathError) Error() string {
@@ -276,7 +287,7 @@ func (err *invalidPathError) Error() string {
}
type invalidPathIterError struct {
- v interface{}
+ v any
}
func (err *invalidPathIterError) Error() string {
@@ -284,24 +295,24 @@ func (err *invalidPathIterError) Error() string {
}
type getpathError struct {
- v, path interface{}
+ v, path any
}
func (err *getpathError) Error() string {
- return "cannot getpath with " + previewValue(err.path) + " against: " + typeErrorPreview(err.v) + ""
+ return "cannot getpath with " + Preview(err.path) + " against: " + typeErrorPreview(err.v)
}
type queryParseError struct {
- typ, fname, contents string
- err error
+ fname, contents string
+ err error
}
-func (err *queryParseError) QueryParseError() (string, string, string, error) {
- return err.typ, err.fname, err.contents, err.err
+func (err *queryParseError) QueryParseError() (string, string, error) {
+ return err.fname, err.contents, err.err
}
func (err *queryParseError) Error() string {
- return "invalid " + err.typ + ": " + err.fname + ": " + err.err.Error()
+ return "invalid query: " + err.fname + ": " + err.err.Error()
}
type jsonParseError struct {
@@ -317,113 +328,13 @@ func (err *jsonParseError) Error() string {
return "invalid json: " + err.fname + ": " + err.err.Error()
}
-func typeErrorPreview(v interface{}) string {
- if _, ok := v.(Iter); ok {
- return "gojq.Iter"
- }
- p := preview(v)
- if p != "" {
- p = " (" + p + ")"
- }
- return typeof(v) + p
-}
-
-func typeof(v interface{}) string {
- switch v := v.(type) {
+func typeErrorPreview(v any) string {
+ switch v.(type) {
case nil:
return "null"
- case bool:
- return "boolean"
- case int, float64, *big.Int:
- return "number"
- case string:
- return "string"
- case []interface{}:
- return "array"
- case map[string]interface{}:
- return "object"
+ case Iter:
+ return "gojq.Iter"
default:
- panic(fmt.Sprintf("invalid value: %v", v))
- }
-}
-
-type limitedWriter struct {
- buf []byte
- off int
-}
-
-func (w *limitedWriter) Write(bs []byte) (int, error) {
- n := copy(w.buf[w.off:], bs)
- if w.off += n; w.off == len(w.buf) {
- panic(nil)
- }
- return n, nil
-}
-
-func (w *limitedWriter) WriteByte(b byte) error {
- w.buf[w.off] = b
- if w.off++; w.off == len(w.buf) {
- panic(nil)
- }
- return nil
-}
-
-func (w *limitedWriter) WriteString(s string) (int, error) {
- n := copy(w.buf[w.off:], s)
- if w.off += n; w.off == len(w.buf) {
- panic(nil)
- }
- return n, nil
-}
-
-func (w *limitedWriter) String() string {
- return string(w.buf[:w.off])
-}
-
-func jsonLimitedMarshal(v interface{}, n int) (s string) {
- w := &limitedWriter{buf: make([]byte, n)}
- defer func() {
- recover()
- s = w.String()
- }()
- (&encoder{w: w}).encode(v)
- return
-}
-
-func preview(v interface{}) string {
- if v == nil {
- return ""
- }
- s := jsonLimitedMarshal(v, 32)
- if l := 30; len(s) > l {
- var trailing string
- switch v.(type) {
- case string:
- trailing = ` ..."`
- case []interface{}:
- trailing = " ...]"
- case map[string]interface{}:
- trailing = " ...}"
- default:
- trailing = " ..."
- }
- var sb strings.Builder
- sb.Grow(l + 5)
- for _, c := range s {
- sb.WriteRune(c)
- if sb.Len() >= l-len(trailing) {
- sb.WriteString(trailing)
- break
- }
- }
- s = sb.String()
- }
- return s
-}
-
-func previewValue(v interface{}) string {
- if v == nil {
- return "null"
+ return TypeOf(v) + " (" + Preview(v) + ")"
}
- return preview(v)
}
diff --git a/vendor/github.com/itchyny/gojq/execute.go b/vendor/github.com/itchyny/gojq/execute.go
index d861c628..d43ef3e9 100644
--- a/vendor/github.com/itchyny/gojq/execute.go
+++ b/vendor/github.com/itchyny/gojq/execute.go
@@ -2,11 +2,12 @@ package gojq
import (
"context"
- "fmt"
+ "math"
+ "reflect"
"sort"
)
-func (env *env) execute(bc *Code, v interface{}, vars ...interface{}) Iter {
+func (env *env) execute(bc *Code, v any, vars ...any) Iter {
env.codes = bc.codes
env.codeinfos = bc.codeinfos
env.push(v)
@@ -17,7 +18,7 @@ func (env *env) execute(bc *Code, v interface{}, vars ...interface{}) Iter {
return env
}
-func (env *env) Next() (interface{}, bool) {
+func (env *env) Next() (any, bool) {
var err error
pc, callpc, index := env.pc, len(env.codes)-1, -1
backtrack, hasCtx := env.backtrack, env.ctx != context.Background()
@@ -42,9 +43,9 @@ loop:
case oppop:
env.pop()
case opdup:
- x := env.pop()
- env.push(x)
- env.push(x)
+ v := env.pop()
+ env.push(v)
+ env.push(v)
case opconst:
env.pop()
env.push(code.v)
@@ -57,7 +58,7 @@ loop:
break loop
}
n := code.v.(int)
- m := make(map[string]interface{}, n)
+ m := make(map[string]any, n)
for i := 0; i < n; i++ {
v, k := env.pop(), env.pop()
s, ok := k.(string)
@@ -70,7 +71,7 @@ loop:
env.push(m)
case opappend:
i := env.index(code.v.([2]int))
- env.values[i] = append(env.values[i].([]interface{}), env.pop())
+ env.values[i] = append(env.values[i].([]any), env.pop())
case opfork:
if backtrack {
if err != nil {
@@ -78,9 +79,8 @@ loop:
}
pc, backtrack = code.v.(int), false
goto loop
- } else {
- env.pushfork(pc)
}
+ env.pushfork(pc)
case opforktrybegin:
if backtrack {
if err == nil {
@@ -90,6 +90,8 @@ loop:
case *tryEndError:
err = er.err
break loop
+ case *breakError:
+ break loop
case ValueError:
if er, ok := er.(*exitCodeError); ok && er.halt {
break loop
@@ -107,18 +109,16 @@ loop:
}
pc, backtrack, err = code.v.(int), false, nil
goto loop
- } else {
- env.pushfork(pc)
}
+ env.pushfork(pc)
case opforktryend:
if backtrack {
if err != nil {
err = &tryEndError{err}
}
break loop
- } else {
- env.pushfork(pc)
}
+ env.pushfork(pc)
case opforkalt:
if backtrack {
if err == nil {
@@ -126,9 +126,8 @@ loop:
}
pc, backtrack, err = code.v.(int), false, nil
goto loop
- } else {
- env.pushfork(pc)
}
+ env.pushfork(pc)
case opforklabel:
if backtrack {
label := env.pop()
@@ -136,13 +135,12 @@ loop:
err = nil
}
break loop
- } else {
- env.push(env.label)
- env.pushfork(pc)
- env.pop()
- env.values[env.index(code.v.([2]int))] = env.label
- env.label++
}
+ env.push(env.label)
+ env.pushfork(pc)
+ env.pop()
+ env.values[env.index(code.v.([2]int))] = env.label
+ env.label++
case opbacktrack:
break loop
case opjump:
@@ -153,6 +151,30 @@ loop:
pc = code.v.(int)
goto loop
}
+ case opindex, opindexarray:
+ if backtrack {
+ break loop
+ }
+ p, v := code.v, env.pop()
+ if code.op == opindexarray && v != nil {
+ if _, ok := v.([]any); !ok {
+ err = &expectedArrayError{v}
+ break loop
+ }
+ }
+ w := funcIndex2(nil, v, p)
+ if e, ok := w.(error); ok {
+ err = e
+ break loop
+ }
+ env.push(w)
+ if !env.paths.empty() && env.expdepth == 0 {
+ if !env.pathIntact(v) {
+ err = &invalidPathError{v}
+ break loop
+ }
+ env.paths.push(pathValue{path: p, value: w})
+ }
case opcall:
if backtrack {
break loop
@@ -161,13 +183,13 @@ loop:
case int:
pc, callpc, index = v, pc, env.scopes.index
goto loop
- case [3]interface{}:
+ case [3]any:
argcnt := v[1].(int)
x, args := env.pop(), env.args[:argcnt]
for i := 0; i < argcnt; i++ {
args[i] = env.pop()
}
- w := v[0].(func(interface{}, []interface{}) interface{})(x, args)
+ w := v[0].(func(any, []any) any)(x, args)
if e, ok := w.(error); ok {
if er, ok := e.(*exitCodeError); !ok || er.value != nil || er.halt {
err = e
@@ -175,14 +197,31 @@ loop:
break loop
}
env.push(w)
- if !env.paths.empty() {
- var ps []interface{}
- ps, err = env.pathEntries(v[2].(string), x, args)
- if err != nil {
- break loop
- }
- for _, p := range ps {
- env.paths.push(pathValue{path: p, value: w})
+ if !env.paths.empty() && env.expdepth == 0 {
+ switch v[2].(string) {
+ case "_index":
+ if x = args[0]; !env.pathIntact(x) {
+ err = &invalidPathError{x}
+ break loop
+ }
+ env.paths.push(pathValue{path: args[1], value: w})
+ case "_slice":
+ if x = args[0]; !env.pathIntact(x) {
+ err = &invalidPathError{x}
+ break loop
+ }
+ env.paths.push(pathValue{
+ path: map[string]any{"start": args[2], "end": args[1]},
+ value: w,
+ })
+ case "getpath":
+ if !env.pathIntact(x) {
+ err = &invalidPathError{x}
+ break loop
+ }
+ for _, p := range args[0].([]any) {
+ env.paths.push(pathValue{path: p, value: w})
+ }
}
}
default:
@@ -199,7 +238,7 @@ loop:
goto loop
case opscope:
xs := code.v.([3]int)
- var saveindex, outerindex, limit int
+ var saveindex, outerindex int
if index == env.scopes.index {
if callpc >= 0 {
saveindex = index
@@ -207,7 +246,7 @@ loop:
callpc, saveindex = env.popscope()
}
} else {
- env.scopes.save(&saveindex, &limit)
+ saveindex, _ = env.scopes.save()
env.scopes.index = index
}
if outerindex = index; outerindex >= 0 {
@@ -218,7 +257,7 @@ loop:
env.scopes.push(scope{xs[0], env.offset, callpc, saveindex, outerindex})
env.offset += xs[1]
if env.offset > len(env.values) {
- vs := make([]interface{}, env.offset*2)
+ vs := make([]any, env.offset*2)
copy(vs, env.values)
env.values = vs
}
@@ -230,7 +269,7 @@ loop:
if env.scopes.empty() {
return env.pop(), true
}
- case opeach:
+ case opiter:
if err != nil {
break loop
}
@@ -239,9 +278,8 @@ loop:
switch v := env.pop().(type) {
case []pathValue:
xs = v
- case []interface{}:
- if !env.paths.empty() && env.expdepth == 0 &&
- !deepEqual(v, env.paths.top().(pathValue).value) {
+ case []any:
+ if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
err = &invalidPathIterError{v}
break loop
}
@@ -252,9 +290,8 @@ loop:
for i, v := range v {
xs[i] = pathValue{path: i, value: v}
}
- case map[string]interface{}:
- if !env.paths.empty() && env.expdepth == 0 &&
- !deepEqual(v, env.paths.top().(pathValue).value) {
+ case map[string]any:
+ if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
err = &invalidPathIterError{v}
break loop
}
@@ -271,10 +308,6 @@ loop:
return xs[i].path.(string) < xs[j].path.(string)
})
case Iter:
- if !env.paths.empty() && env.expdepth == 0 {
- err = &invalidPathIterError{v}
- break loop
- }
if w, ok := v.Next(); ok {
env.push(v)
env.pushfork(pc)
@@ -289,6 +322,7 @@ loop:
break loop
default:
err = &iteratorError{v}
+ env.push(emptyIter{})
break loop
}
if len(xs) > 1 {
@@ -312,18 +346,13 @@ loop:
if backtrack {
break loop
}
- if env.expdepth > 0 {
- panic(fmt.Sprintf("unexpected expdepth: %d", env.expdepth))
- }
env.pop()
- x := env.pop()
- if deepEqual(x, env.paths.top().(pathValue).value) {
- env.push(env.poppaths())
- env.expdepth = env.paths.pop().(int)
- } else {
- err = &invalidPathError{x}
+ if v := env.pop(); !env.pathIntact(v) {
+ err = &invalidPathError{v}
break loop
}
+ env.push(env.poppaths())
+ env.expdepth = env.paths.pop().(int)
default:
panic(code.op)
}
@@ -338,11 +367,11 @@ loop:
return nil, false
}
-func (env *env) push(v interface{}) {
+func (env *env) push(v any) {
env.stack.push(v)
}
-func (env *env) pop() interface{} {
+func (env *env) pop() any {
return env.stack.pop()
}
@@ -357,9 +386,9 @@ func (env *env) popscope() (int, int) {
func (env *env) pushfork(pc int) {
f := fork{pc: pc, expdepth: env.expdepth}
- env.stack.save(&f.stackindex, &f.stacklimit)
- env.scopes.save(&f.scopeindex, &f.scopelimit)
- env.paths.save(&f.pathindex, &f.pathlimit)
+ f.stackindex, f.stacklimit = env.stack.save()
+ f.scopeindex, f.scopelimit = env.scopes.save()
+ f.pathindex, f.pathlimit = env.paths.save()
env.forks = append(env.forks, f)
env.debugForks(pc, ">>>")
}
@@ -386,39 +415,28 @@ func (env *env) index(v [2]int) int {
}
type pathValue struct {
- path, value interface{}
+ path, value any
}
-func (env *env) pathEntries(name string, x interface{}, args []interface{}) ([]interface{}, error) {
- switch name {
- case "_index":
- if env.expdepth > 0 {
- return nil, nil
- } else if !deepEqual(args[0], env.paths.top().(pathValue).value) {
- return nil, &invalidPathError{x}
- }
- return []interface{}{args[1]}, nil
- case "_slice":
- if env.expdepth > 0 {
- return nil, nil
- } else if !deepEqual(args[0], env.paths.top().(pathValue).value) {
- return nil, &invalidPathError{x}
+func (env *env) pathIntact(v any) bool {
+ w := env.paths.top().(pathValue).value
+ switch v := v.(type) {
+ case []any, map[string]any:
+ switch w.(type) {
+ case []any, map[string]any:
+ v, w := reflect.ValueOf(v), reflect.ValueOf(w)
+ return v.Pointer() == w.Pointer() && v.Len() == w.Len()
}
- return []interface{}{map[string]interface{}{"start": args[2], "end": args[1]}}, nil
- case "getpath":
- if env.expdepth > 0 {
- return nil, nil
- } else if !deepEqual(x, env.paths.top().(pathValue).value) {
- return nil, &invalidPathError{x}
+ case float64:
+ if w, ok := w.(float64); ok {
+ return v == w || math.IsNaN(v) && math.IsNaN(w)
}
- return args[0].([]interface{}), nil
- default:
- return nil, nil
}
+ return v == w
}
-func (env *env) poppaths() []interface{} {
- var xs []interface{}
+func (env *env) poppaths() []any {
+ var xs []any
for {
p := env.paths.pop().(pathValue)
if p.path == nil {
diff --git a/vendor/github.com/itchyny/gojq/func.go b/vendor/github.com/itchyny/gojq/func.go
index ca4caa69..d94a7a47 100644
--- a/vendor/github.com/itchyny/gojq/func.go
+++ b/vendor/github.com/itchyny/gojq/func.go
@@ -4,9 +4,11 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
+ "io"
"math"
"math/big"
"net/url"
+ "reflect"
"regexp"
"sort"
"strconv"
@@ -30,7 +32,7 @@ const (
type function struct {
argcount int
iter bool
- callback func(interface{}, []interface{}) interface{}
+ callback func(any, []any) any
}
func (fn function) accept(cnt int) bool {
@@ -51,15 +53,26 @@ func init() {
"utf8bytelength": argFunc0(funcUtf8ByteLength),
"keys": argFunc0(funcKeys),
"has": argFunc1(funcHas),
+ "to_entries": argFunc0(funcToEntries),
+ "from_entries": argFunc0(funcFromEntries),
"add": argFunc0(funcAdd),
"tonumber": argFunc0(funcToNumber),
"tostring": argFunc0(funcToString),
"type": argFunc0(funcType),
"reverse": argFunc0(funcReverse),
"contains": argFunc1(funcContains),
+ "indices": argFunc1(funcIndices),
+ "index": argFunc1(funcIndex),
+ "rindex": argFunc1(funcRindex),
+ "startswith": argFunc1(funcStartsWith),
+ "endswith": argFunc1(funcEndsWith),
+ "ltrimstr": argFunc1(funcLtrimstr),
+ "rtrimstr": argFunc1(funcRtrimstr),
"explode": argFunc0(funcExplode),
"implode": argFunc0(funcImplode),
"split": {argcount1 | argcount2, false, funcSplit},
+ "ascii_downcase": argFunc0(funcASCIIDowncase),
+ "ascii_upcase": argFunc0(funcASCIIUpcase),
"tojson": argFunc0(funcToJSON),
"fromjson": argFunc0(funcFromJSON),
"format": argFunc1(funcFormat),
@@ -70,11 +83,8 @@ func init() {
"_tosh": argFunc0(funcToSh),
"_tobase64": argFunc0(funcToBase64),
"_tobase64d": argFunc0(funcToBase64d),
- "_index": argFunc2(funcIndex),
+ "_index": argFunc2(funcIndex2),
"_slice": argFunc3(funcSlice),
- "_indices": argFunc1(funcIndices),
- "_lindex": argFunc1(funcLindex),
- "_rindex": argFunc1(funcRindex),
"_plus": argFunc0(funcOpPlus),
"_negate": argFunc0(funcOpNegate),
"_add": argFunc2(funcOpAdd),
@@ -89,13 +99,18 @@ func init() {
"_less": argFunc2(funcOpLt),
"_greatereq": argFunc2(funcOpGe),
"_lesseq": argFunc2(funcOpLe),
+ "flatten": {argcount0 | argcount1, false, funcFlatten},
"_range": {argcount3, true, funcRange},
+ "min": argFunc0(funcMin),
"_min_by": argFunc1(funcMinBy),
+ "max": argFunc0(funcMax),
"_max_by": argFunc1(funcMaxBy),
+ "sort": argFunc0(funcSort),
"_sort_by": argFunc1(funcSortBy),
"_group_by": argFunc1(funcGroupBy),
+ "unique": argFunc0(funcUnique),
"_unique_by": argFunc1(funcUniqueBy),
- "_join": argFunc1(funcJoin),
+ "join": argFunc1(funcJoin),
"sin": mathFunc("sin", math.Sin),
"cos": mathFunc("cos", math.Cos),
"tan": mathFunc("tan", math.Tan),
@@ -176,47 +191,47 @@ func init() {
"strptime": argFunc1(funcStrptime),
"now": argFunc0(funcNow),
"_match": argFunc3(funcMatch),
+ "_capture": argFunc0(funcCapture),
"error": {argcount0 | argcount1, false, funcError},
"halt": argFunc0(funcHalt),
"halt_error": {argcount0 | argcount1, false, funcHaltError},
- "_type_error": argFunc1(internalfuncTypeError),
}
}
-func argFunc0(fn func(interface{}) interface{}) function {
+func argFunc0(f func(any) any) function {
return function{
- argcount0, false, func(v interface{}, _ []interface{}) interface{} {
- return fn(v)
+ argcount0, false, func(v any, _ []any) any {
+ return f(v)
},
}
}
-func argFunc1(fn func(_, _ interface{}) interface{}) function {
+func argFunc1(f func(_, _ any) any) function {
return function{
- argcount1, false, func(v interface{}, args []interface{}) interface{} {
- return fn(v, args[0])
+ argcount1, false, func(v any, args []any) any {
+ return f(v, args[0])
},
}
}
-func argFunc2(fn func(_, _, _ interface{}) interface{}) function {
+func argFunc2(f func(_, _, _ any) any) function {
return function{
- argcount2, false, func(v interface{}, args []interface{}) interface{} {
- return fn(v, args[0], args[1])
+ argcount2, false, func(v any, args []any) any {
+ return f(v, args[0], args[1])
},
}
}
-func argFunc3(fn func(_, _, _, _ interface{}) interface{}) function {
+func argFunc3(f func(_, _, _, _ any) any) function {
return function{
- argcount3, false, func(v interface{}, args []interface{}) interface{} {
- return fn(v, args[0], args[1], args[2])
+ argcount3, false, func(v any, args []any) any {
+ return f(v, args[0], args[1], args[2])
},
}
}
func mathFunc(name string, f func(float64) float64) function {
- return argFunc0(func(v interface{}) interface{} {
+ return argFunc0(func(v any) any {
x, ok := toFloat(v)
if !ok {
return &funcTypeError{name, v}
@@ -226,7 +241,7 @@ func mathFunc(name string, f func(float64) float64) function {
}
func mathFunc2(name string, f func(_, _ float64) float64) function {
- return argFunc2(func(_, x, y interface{}) interface{} {
+ return argFunc2(func(_, x, y any) any {
l, ok := toFloat(x)
if !ok {
return &funcTypeError{name, x}
@@ -240,7 +255,7 @@ func mathFunc2(name string, f func(_, _ float64) float64) function {
}
func mathFunc3(name string, f func(_, _, _ float64) float64) function {
- return argFunc3(func(_, a, b, c interface{}) interface{} {
+ return argFunc3(func(_, a, b, c any) any {
x, ok := toFloat(a)
if !ok {
return &funcTypeError{name, a}
@@ -257,14 +272,10 @@ func mathFunc3(name string, f func(_, _, _ float64) float64) function {
})
}
-func funcLength(v interface{}) interface{} {
+func funcLength(v any) any {
switch v := v.(type) {
- case []interface{}:
- return len(v)
- case map[string]interface{}:
- return len(v)
- case string:
- return len([]rune(v))
+ case nil:
+ return 0
case int:
if v >= 0 {
return v
@@ -277,128 +288,207 @@ func funcLength(v interface{}) interface{} {
return v
}
return new(big.Int).Abs(v)
- case nil:
- return 0
+ case string:
+ return len([]rune(v))
+ case []any:
+ return len(v)
+ case map[string]any:
+ return len(v)
default:
return &funcTypeError{"length", v}
}
}
-func funcUtf8ByteLength(v interface{}) interface{} {
- switch v := v.(type) {
- case string:
- return len(v)
- default:
+func funcUtf8ByteLength(v any) any {
+ s, ok := v.(string)
+ if !ok {
return &funcTypeError{"utf8bytelength", v}
}
+ return len(s)
}
-func funcKeys(v interface{}) interface{} {
+func funcKeys(v any) any {
switch v := v.(type) {
- case []interface{}:
- w := make([]interface{}, len(v))
+ case []any:
+ w := make([]any, len(v))
for i := range v {
w[i] = i
}
return w
- case map[string]interface{}:
- w := make([]string, len(v))
- var i int
- for k := range v {
+ case map[string]any:
+ w := make([]any, len(v))
+ for i, k := range keys(v) {
w[i] = k
- i++
}
- sort.Strings(w)
- u := make([]interface{}, len(v))
- for i, x := range w {
- u[i] = x
- }
- return u
+ return w
default:
return &funcTypeError{"keys", v}
}
}
-func funcHas(v, x interface{}) interface{} {
+func keys(v map[string]any) []string {
+ w := make([]string, len(v))
+ var i int
+ for k := range v {
+ w[i] = k
+ i++
+ }
+ sort.Strings(w)
+ return w
+}
+
+func values(v any) ([]any, bool) {
+ switch v := v.(type) {
+ case []any:
+ return v, true
+ case map[string]any:
+ vs := make([]any, len(v))
+ for i, k := range keys(v) {
+ vs[i] = v[k]
+ }
+ return vs, true
+ default:
+ return nil, false
+ }
+}
+
+func funcHas(v, x any) any {
switch v := v.(type) {
- case []interface{}:
+ case []any:
if x, ok := toInt(x); ok {
return 0 <= x && x < len(v)
}
- return &hasKeyTypeError{v, x}
- case map[string]interface{}:
- switch x := x.(type) {
- case string:
+ case map[string]any:
+ if x, ok := x.(string); ok {
_, ok := v[x]
return ok
- default:
- return &hasKeyTypeError{v, x}
}
case nil:
return false
- default:
- return &hasKeyTypeError{v, x}
}
+ return &hasKeyTypeError{v, x}
}
-func funcAdd(v interface{}) interface{} {
- if vs, ok := v.(map[string]interface{}); ok {
- xs := make([]string, len(vs))
- var i int
- for k := range vs {
- xs[i] = k
- i++
+func funcToEntries(v any) any {
+ switch v := v.(type) {
+ case []any:
+ w := make([]any, len(v))
+ for i, x := range v {
+ w[i] = map[string]any{"key": i, "value": x}
+ }
+ return w
+ case map[string]any:
+ w := make([]any, len(v))
+ for i, k := range keys(v) {
+ w[i] = map[string]any{"key": k, "value": v[k]}
}
- sort.Strings(xs)
- us := make([]interface{}, len(vs))
- for i, x := range xs {
- us[i] = vs[x]
+ return w
+ default:
+ return &funcTypeError{"to_entries", v}
+ }
+}
+
+func funcFromEntries(v any) any {
+ vs, ok := v.([]any)
+ if !ok {
+ return &funcTypeError{"from_entries", v}
+ }
+ w := make(map[string]any, len(vs))
+ for _, v := range vs {
+ switch v := v.(type) {
+ case map[string]any:
+ var (
+ key string
+ value any
+ ok bool
+ )
+ for _, k := range [4]string{"key", "Key", "name", "Name"} {
+ if k := v[k]; k != nil && k != false {
+ if key, ok = k.(string); !ok {
+ return &objectKeyNotStringError{k}
+ }
+ break
+ }
+ }
+ if !ok {
+ return &objectKeyNotStringError{nil}
+ }
+ for _, k := range [2]string{"value", "Value"} {
+ if value, ok = v[k]; ok {
+ break
+ }
+ }
+ w[key] = value
+ default:
+ return &funcTypeError{"from_entries", v}
}
- v = us
}
- vs, ok := v.([]interface{})
+ return w
+}
+
+func funcAdd(v any) any {
+ vs, ok := values(v)
if !ok {
return &funcTypeError{"add", v}
}
v = nil
for _, x := range vs {
- switch y := x.(type) {
- case map[string]interface{}:
+ switch x := x.(type) {
+ case nil:
+ continue
+ case string:
switch w := v.(type) {
case nil:
- m := make(map[string]interface{}, len(y))
- for k, e := range y {
- m[k] = e
- }
- v = m
+ var sb strings.Builder
+ sb.WriteString(x)
+ v = &sb
continue
- case map[string]interface{}:
- for k, e := range y {
- w[k] = e
- }
+ case *strings.Builder:
+ w.WriteString(x)
continue
}
- case []interface{}:
+ case []any:
switch w := v.(type) {
case nil:
- s := make([]interface{}, len(y))
- copy(s, y)
+ s := make([]any, len(x))
+ copy(s, x)
v = s
continue
- case []interface{}:
- v = append(w, y...)
+ case []any:
+ v = append(w, x...)
+ continue
+ }
+ case map[string]any:
+ switch w := v.(type) {
+ case nil:
+ m := make(map[string]any, len(x))
+ for k, e := range x {
+ m[k] = e
+ }
+ v = m
+ continue
+ case map[string]any:
+ for k, e := range x {
+ w[k] = e
+ }
continue
}
}
+ if sb, ok := v.(*strings.Builder); ok {
+ v = sb.String()
+ }
v = funcOpAdd(nil, v, x)
if err, ok := v.(error); ok {
return err
}
}
+ if sb, ok := v.(*strings.Builder); ok {
+ v = sb.String()
+ }
return v
}
-func funcToNumber(v interface{}) interface{} {
+func funcToNumber(v any) any {
switch v := v.(type) {
case int, float64, *big.Int:
return v
@@ -406,130 +496,227 @@ func funcToNumber(v interface{}) interface{} {
if !newLexer(v).validNumber() {
return fmt.Errorf("invalid number: %q", v)
}
- return normalizeNumber(json.Number(v))
+ return toNumber(v)
default:
return &funcTypeError{"tonumber", v}
}
}
-func funcToString(v interface{}) interface{} {
+func toNumber(v string) any {
+ return normalizeNumber(json.Number(v))
+}
+
+func funcToString(v any) any {
if s, ok := v.(string); ok {
return s
}
return funcToJSON(v)
}
-func funcType(v interface{}) interface{} {
- return typeof(v)
+func funcType(v any) any {
+ return TypeOf(v)
}
-func funcReverse(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcReverse(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &expectedArrayError{v}
+ return &funcTypeError{"reverse", v}
}
- ws := make([]interface{}, len(vs))
+ ws := make([]any, len(vs))
for i, v := range vs {
ws[len(ws)-i-1] = v
}
return ws
}
-func funcContains(v, x interface{}) interface{} {
- switch v := v.(type) {
- case nil:
- if x == nil {
- return true
- }
- case bool:
- switch x := x.(type) {
- case bool:
- if v == x {
- return true
- }
- }
- }
+func funcContains(v, x any) any {
return binopTypeSwitch(v, x,
- func(l, r int) interface{} { return l == r },
- func(l, r float64) interface{} { return l == r },
- func(l, r *big.Int) interface{} { return l.Cmp(r) == 0 },
- func(l, r string) interface{} { return strings.Contains(l, r) },
- func(l, r []interface{}) interface{} {
- for _, x := range r {
- var found bool
- for _, y := range l {
- if funcContains(y, x) == true {
- found = true
- break
+ func(l, r int) any { return l == r },
+ func(l, r float64) any { return l == r },
+ func(l, r *big.Int) any { return l.Cmp(r) == 0 },
+ func(l, r string) any { return strings.Contains(l, r) },
+ func(l, r []any) any {
+ R:
+ for _, r := range r {
+ for _, l := range l {
+ if funcContains(l, r) == true {
+ continue R
}
}
- if !found {
- return false
- }
+ return false
}
return true
},
- func(l, r map[string]interface{}) interface{} {
- for k, rk := range r {
- lk, ok := l[k]
- if !ok {
- return false
- }
- c := funcContains(lk, rk)
- if _, ok := c.(error); ok {
- return false
- }
- if c == false {
+ func(l, r map[string]any) any {
+ if len(l) < len(r) {
+ return false
+ }
+ for k, r := range r {
+ if l, ok := l[k]; !ok || funcContains(l, r) != true {
return false
}
}
return true
},
- func(l, r interface{}) interface{} { return &funcContainsError{l, r} },
+ func(l, r any) any {
+ if l == r {
+ return true
+ }
+ return &containsTypeError{l, r}
+ },
)
}
-func funcExplode(v interface{}) interface{} {
+func funcIndices(v, x any) any {
+ return indexFunc(v, x, indices)
+}
+
+func indices(vs, xs []any) any {
+ var rs []any
+ if len(xs) == 0 {
+ return rs
+ }
+ for i := 0; i <= len(vs)-len(xs); i++ {
+ if compare(vs[i:i+len(xs)], xs) == 0 {
+ rs = append(rs, i)
+ }
+ }
+ return rs
+}
+
+func funcIndex(v, x any) any {
+ return indexFunc(v, x, func(vs, xs []any) any {
+ if len(xs) == 0 {
+ return nil
+ }
+ for i := 0; i <= len(vs)-len(xs); i++ {
+ if compare(vs[i:i+len(xs)], xs) == 0 {
+ return i
+ }
+ }
+ return nil
+ })
+}
+
+func funcRindex(v, x any) any {
+ return indexFunc(v, x, func(vs, xs []any) any {
+ if len(xs) == 0 {
+ return nil
+ }
+ for i := len(vs) - len(xs); i >= 0; i-- {
+ if compare(vs[i:i+len(xs)], xs) == 0 {
+ return i
+ }
+ }
+ return nil
+ })
+}
+
+func indexFunc(v, x any, f func(_, _ []any) any) any {
switch v := v.(type) {
+ case nil:
+ return nil
+ case []any:
+ switch x := x.(type) {
+ case []any:
+ return f(v, x)
+ default:
+ return f(v, []any{x})
+ }
case string:
- return explode(v)
+ if x, ok := x.(string); ok {
+ return f(explode(v), explode(x))
+ }
+ return &expectedStringError{x}
default:
+ return &expectedArrayError{v}
+ }
+}
+
+func funcStartsWith(v, x any) any {
+ s, ok := v.(string)
+ if !ok {
+ return &funcTypeError{"startswith", v}
+ }
+ t, ok := x.(string)
+ if !ok {
+ return &funcTypeError{"startswith", x}
+ }
+ return strings.HasPrefix(s, t)
+}
+
+func funcEndsWith(v, x any) any {
+ s, ok := v.(string)
+ if !ok {
+ return &funcTypeError{"endswith", v}
+ }
+ t, ok := x.(string)
+ if !ok {
+ return &funcTypeError{"endswith", x}
+ }
+ return strings.HasSuffix(s, t)
+}
+
+func funcLtrimstr(v, x any) any {
+ s, ok := v.(string)
+ if !ok {
+ return v
+ }
+ t, ok := x.(string)
+ if !ok {
+ return v
+ }
+ return strings.TrimPrefix(s, t)
+}
+
+func funcRtrimstr(v, x any) any {
+ s, ok := v.(string)
+ if !ok {
+ return v
+ }
+ t, ok := x.(string)
+ if !ok {
+ return v
+ }
+ return strings.TrimSuffix(s, t)
+}
+
+func funcExplode(v any) any {
+ s, ok := v.(string)
+ if !ok {
return &funcTypeError{"explode", v}
}
+ return explode(s)
}
-func explode(s string) []interface{} {
- rs := []int32(s)
- xs := make([]interface{}, len(rs))
- for i, r := range rs {
+func explode(s string) []any {
+ xs := make([]any, len([]rune(s)))
+ var i int
+ for _, r := range s {
xs[i] = int(r)
+ i++
}
return xs
}
-func funcImplode(v interface{}) interface{} {
- switch v := v.(type) {
- case []interface{}:
- return implode(v)
- default:
+func funcImplode(v any) any {
+ vs, ok := v.([]any)
+ if !ok {
return &funcTypeError{"implode", v}
}
-}
-
-func implode(v []interface{}) interface{} {
var sb strings.Builder
- sb.Grow(len(v))
- for _, r := range v {
- if r, ok := toInt(r); ok && 0 <= r && r <= utf8.MaxRune {
+ sb.Grow(len(vs))
+ for _, v := range vs {
+ if r, ok := toInt(v); ok && 0 <= r && r <= utf8.MaxRune {
sb.WriteRune(rune(r))
} else {
- return &funcTypeError{"implode", v}
+ return &funcTypeError{"implode", vs}
}
}
return sb.String()
}
-func funcSplit(v interface{}, args []interface{}) interface{} {
+func funcSplit(v any, args []any) any {
s, ok := v.(string)
if !ok {
return &funcTypeError{"split", v}
@@ -556,43 +743,71 @@ func funcSplit(v interface{}, args []interface{}) interface{} {
}
ss = r.Split(s, -1)
}
- xs := make([]interface{}, len(ss))
+ xs := make([]any, len(ss))
for i, s := range ss {
xs[i] = s
}
return xs
}
-func funcToJSON(v interface{}) interface{} {
- return jsonMarshal(v)
+func funcASCIIDowncase(v any) any {
+ s, ok := v.(string)
+ if !ok {
+ return &funcTypeError{"ascii_downcase", v}
+ }
+ return strings.Map(func(r rune) rune {
+ if 'A' <= r && r <= 'Z' {
+ return r + ('a' - 'A')
+ }
+ return r
+ }, s)
}
-func funcFromJSON(v interface{}) interface{} {
- switch v := v.(type) {
- case string:
- var w interface{}
- err := json.Unmarshal([]byte(v), &w)
- if err != nil {
- return err
+func funcASCIIUpcase(v any) any {
+ s, ok := v.(string)
+ if !ok {
+ return &funcTypeError{"ascii_upcase", v}
+ }
+ return strings.Map(func(r rune) rune {
+ if 'a' <= r && r <= 'z' {
+ return r - ('a' - 'A')
}
- return w
- default:
+ return r
+ }, s)
+}
+
+func funcToJSON(v any) any {
+ return jsonMarshal(v)
+}
+
+func funcFromJSON(v any) any {
+ s, ok := v.(string)
+ if !ok {
return &funcTypeError{"fromjson", v}
}
+ var w any
+ dec := json.NewDecoder(strings.NewReader(s))
+ dec.UseNumber()
+ if err := dec.Decode(&w); err != nil {
+ return err
+ }
+ if _, err := dec.Token(); err != io.EOF {
+ return &funcTypeError{"fromjson", v}
+ }
+ return normalizeNumbers(w)
}
-func funcFormat(v, x interface{}) interface{} {
- switch x := x.(type) {
- case string:
- fmt := "@" + x
- f := formatToFunc(fmt)
- if f == nil {
- return &formatNotFoundError{fmt}
- }
- return internalFuncs[f.Name].callback(v, nil)
- default:
+func funcFormat(v, x any) any {
+ s, ok := x.(string)
+ if !ok {
return &funcTypeError{"format", x}
}
+ format := "@" + s
+ f := formatToFunc(format)
+ if f == nil {
+ return &formatNotFoundError{format}
+ }
+ return internalFuncs[f.Name].callback(v, nil)
}
var htmlEscaper = strings.NewReplacer(
@@ -603,7 +818,7 @@ var htmlEscaper = strings.NewReplacer(
`"`, """,
)
-func funcToHTML(v interface{}) interface{} {
+func funcToHTML(v any) any {
switch x := funcToString(v).(type) {
case string:
return htmlEscaper.Replace(x)
@@ -612,7 +827,7 @@ func funcToHTML(v interface{}) interface{} {
}
}
-func funcToURI(v interface{}) interface{} {
+func funcToURI(v any) any {
switch x := funcToString(v).(type) {
case string:
return url.QueryEscape(x)
@@ -621,9 +836,14 @@ func funcToURI(v interface{}) interface{} {
}
}
-func funcToCSV(v interface{}) interface{} {
- return funcToCSVTSV("csv", v, ",", func(s string) string {
- return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
+var csvEscaper = strings.NewReplacer(
+ `"`, `""`,
+ "\x00", `\0`,
+)
+
+func funcToCSV(v any) any {
+ return formatJoin("csv", v, ",", func(s string) string {
+ return `"` + csvEscaper.Replace(s) + `"`
})
}
@@ -632,72 +852,49 @@ var tsvEscaper = strings.NewReplacer(
"\r", `\r`,
"\n", `\n`,
"\\", `\\`,
+ "\x00", `\0`,
)
-func funcToTSV(v interface{}) interface{} {
- return funcToCSVTSV("tsv", v, "\t", func(s string) string {
- return tsvEscaper.Replace(s)
- })
+func funcToTSV(v any) any {
+ return formatJoin("tsv", v, "\t", tsvEscaper.Replace)
}
-func funcToCSVTSV(typ string, v interface{}, sep string, escape func(string) string) interface{} {
- switch xs := v.(type) {
- case []interface{}:
- ys := make([]string, len(xs))
- for i, x := range xs {
- y, err := toCSVTSV(typ, x, escape)
- if err != nil {
- return err
- }
- ys[i] = y
- }
- return strings.Join(ys, sep)
- default:
- return &expectedArrayError{v}
- }
-}
+var shEscaper = strings.NewReplacer(
+ "'", `'\''`,
+ "\x00", `\0`,
+)
-func toCSVTSV(typ string, v interface{}, escape func(string) string) (string, error) {
- switch v := v.(type) {
- case map[string]interface{}, []interface{}:
- return "", &formatCsvTsvRowError{typ, v}
- case string:
- return escape(v), nil
- default:
- if s := jsonMarshal(v); s != "null" {
- return s, nil
- }
- return "", nil
+func funcToSh(v any) any {
+ if _, ok := v.([]any); !ok {
+ v = []any{v}
}
+ return formatJoin("sh", v, " ", func(s string) string {
+ return "'" + shEscaper.Replace(s) + "'"
+ })
}
-func funcToSh(v interface{}) interface{} {
- var xs []interface{}
- if w, ok := v.([]interface{}); ok {
- xs = w
- } else {
- xs = []interface{}{v}
+func formatJoin(typ string, v any, sep string, escape func(string) string) any {
+ vs, ok := v.([]any)
+ if !ok {
+ return &funcTypeError{"@" + typ, v}
}
- var s strings.Builder
- for i, x := range xs {
- if i > 0 {
- s.WriteByte(' ')
- }
- switch x := x.(type) {
- case map[string]interface{}, []interface{}:
- return &formatShError{x}
+ ss := make([]string, len(vs))
+ for i, v := range vs {
+ switch v := v.(type) {
+ case []any, map[string]any:
+ return &formatRowError{typ, v}
case string:
- s.WriteByte('\'')
- s.WriteString(strings.ReplaceAll(x, "'", `'\''`))
- s.WriteByte('\'')
+ ss[i] = escape(v)
default:
- s.WriteString(jsonMarshal(x))
+ if s := jsonMarshal(v); s != "null" || typ == "sh" {
+ ss[i] = s
+ }
}
}
- return s.String()
+ return strings.Join(ss, sep)
}
-func funcToBase64(v interface{}) interface{} {
+func funcToBase64(v any) any {
switch x := funcToString(v).(type) {
case string:
return base64.StdEncoding.EncodeToString([]byte(x))
@@ -706,7 +903,7 @@ func funcToBase64(v interface{}) interface{} {
}
}
-func funcToBase64d(v interface{}) interface{} {
+func funcToBase64d(v any) any {
switch x := funcToString(v).(type) {
case string:
if i := strings.IndexRune(x, base64.StdPadding); i >= 0 {
@@ -722,48 +919,39 @@ func funcToBase64d(v interface{}) interface{} {
}
}
-func funcIndex(_, v, x interface{}) interface{} {
+func funcIndex2(_, v, x any) any {
switch x := x.(type) {
case string:
switch v := v.(type) {
case nil:
return nil
- case map[string]interface{}:
+ case map[string]any:
return v[x]
default:
return &expectedObjectError{v}
}
case int, float64, *big.Int:
- idx, _ := toInt(x)
+ i, _ := toInt(x)
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
- return funcIndexSlice(nil, nil, &idx, v)
+ case []any:
+ return index(v, i)
case string:
- switch v := funcIndexSlice(nil, nil, &idx, explode(v)).(type) {
- case []interface{}:
- return implode(v)
- case int:
- return implode([]interface{}{v})
- case nil:
- return ""
- default:
- panic(v)
- }
+ return indexString(v, i)
default:
return &expectedArrayError{v}
}
- case []interface{}:
+ case []any:
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
+ case []any:
return indices(v, x)
default:
return &expectedArrayError{v}
}
- case map[string]interface{}:
+ case map[string]any:
if v == nil {
return nil
}
@@ -777,192 +965,163 @@ func funcIndex(_, v, x interface{}) interface{} {
}
return funcSlice(nil, v, end, start)
default:
- return &objectKeyNotStringError{x}
+ switch v.(type) {
+ case []any:
+ return &arrayIndexNotNumberError{x}
+ case string:
+ return &stringIndexNotNumberError{x}
+ default:
+ return &objectKeyNotStringError{x}
+ }
}
}
-func indices(vs, xs []interface{}) interface{} {
- var rs []interface{}
- if len(xs) == 0 {
- return rs
+func index(vs []any, i int) any {
+ i = clampIndex(i, -1, len(vs))
+ if 0 <= i && i < len(vs) {
+ return vs[i]
}
- for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
- var neq bool
- for j, y := range xs {
- if neq = compare(vs[i+j], y) != 0; neq {
- break
+ return nil
+}
+
+func indexString(s string, i int) any {
+ l := len([]rune(s))
+ i = clampIndex(i, -1, l)
+ if 0 <= i && i < l {
+ for _, r := range s {
+ if i--; i < 0 {
+ return string(r)
}
}
- if !neq {
- rs = append(rs, i)
- }
}
- return rs
+ return nil
}
-func funcSlice(_, v, end, start interface{}) (r interface{}) {
- if w, ok := v.(string); ok {
- v = explode(w)
- defer func() {
- switch s := r.(type) {
- case []interface{}:
- r = implode(s)
- case int:
- r = implode([]interface{}{s})
- case nil:
- r = ""
- case error:
- default:
- panic(r)
- }
- }()
- }
+func funcSlice(_, v, e, s any) (r any) {
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
- if start != nil {
- if start, ok := toInt(start); ok {
- if end != nil {
- if end, ok := toInt(end); ok {
- return funcIndexSlice(&start, &end, nil, v)
- }
- return &arrayIndexNotNumberError{end}
- }
- return funcIndexSlice(&start, nil, nil, v)
- }
- return &arrayIndexNotNumberError{start}
- }
- if end != nil {
- if end, ok := toInt(end); ok {
- return funcIndexSlice(nil, &end, nil, v)
- }
- return &arrayIndexNotNumberError{end}
- }
- return v
+ case []any:
+ return slice(v, e, s)
+ case string:
+ return sliceString(v, e, s)
default:
return &expectedArrayError{v}
}
}
-func funcIndexSlice(start, end, index *int, a []interface{}) interface{} {
- aa := a
- if index != nil {
- i := toIndex(aa, *index)
- if i < 0 {
- return nil
+func slice(vs []any, e, s any) any {
+ var start, end int
+ if s != nil {
+ if i, ok := toInt(s); ok {
+ start = clampIndex(i, 0, len(vs))
+ } else {
+ return &arrayIndexNotNumberError{s}
}
- return a[i]
}
- if end != nil {
- i := toIndex(aa, *end)
- if i == -1 {
- i = len(a)
- } else if i == -2 {
- i = 0
+ if e != nil {
+ if i, ok := toInt(e); ok {
+ end = clampIndex(i, start, len(vs))
+ } else {
+ return &arrayIndexNotNumberError{e}
+ }
+ } else {
+ end = len(vs)
+ }
+ return vs[start:end]
+}
+
+func sliceString(v string, e, s any) any {
+ var start, end int
+ l := len([]rune(v))
+ if s != nil {
+ if i, ok := toInt(s); ok {
+ start = clampIndex(i, 0, l)
+ } else {
+ return &stringIndexNotNumberError{s}
+ }
+ }
+ if e != nil {
+ if i, ok := toInt(e); ok {
+ end = clampIndex(i, start, l)
+ } else {
+ return &stringIndexNotNumberError{e}
+ }
+ } else {
+ end = l
+ }
+ if start < l {
+ for i := range v {
+ if start--; start < 0 {
+ start = i
+ break
+ }
}
- a = a[:i]
+ } else {
+ start = len(v)
}
- if start != nil {
- i := toIndex(aa, *start)
- if i == -1 || len(a) < i {
- i = len(a)
- } else if i == -2 {
- i = 0
+ if end < l {
+ for i := range v {
+ if end--; end < 0 {
+ end = i
+ break
+ }
}
- a = a[i:]
+ } else {
+ end = len(v)
}
- return a
+ return v[start:end]
}
-func toIndex(a []interface{}, i int) int {
- l := len(a)
- switch {
- case i < -l:
- return -2
- case i < 0:
- return l + i
- case i < l:
+func clampIndex(i, min, max int) int {
+ if i < 0 {
+ i += max
+ }
+ if i < min {
+ return min
+ } else if i < max {
return i
- default:
- return -1
+ } else {
+ return max
}
}
-func funcIndices(v, x interface{}) interface{} {
- return indexFunc(v, x, indices)
-}
-
-func funcLindex(v, x interface{}) interface{} {
- return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
- if len(xs) == 0 {
- return nil
- }
- for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
- var neq bool
- for j, y := range xs {
- if neq = compare(vs[i+j], y) != 0; neq {
- break
- }
- }
- if !neq {
- return i
- }
- }
- return nil
- })
-}
-
-func funcRindex(v, x interface{}) interface{} {
- return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
- if len(xs) == 0 {
- return nil
- }
- i := len(vs) - 1
- if j := len(vs) - len(xs); j < i {
- i = j
+func funcFlatten(v any, args []any) any {
+ vs, ok := values(v)
+ if !ok {
+ return &funcTypeError{"flatten", v}
+ }
+ var depth float64
+ if len(args) == 0 {
+ depth = -1
+ } else {
+ depth, ok = toFloat(args[0])
+ if !ok {
+ return &funcTypeError{"flatten", args[0]}
}
- for ; i >= 0; i-- {
- var neq bool
- for j, y := range xs {
- if neq = compare(vs[i+j], y) != 0; neq {
- break
- }
- }
- if !neq {
- return i
- }
+ if depth < 0 {
+ return &flattenDepthError{depth}
}
- return nil
- })
+ }
+ return flatten(nil, vs, depth)
}
-func indexFunc(v, x interface{}, f func(_, _ []interface{}) interface{}) interface{} {
- switch v := v.(type) {
- case nil:
- return nil
- case []interface{}:
- switch x := x.(type) {
- case []interface{}:
- return f(v, x)
- default:
- return f(v, []interface{}{x})
- }
- case string:
- if x, ok := x.(string); ok {
- return f(explode(v), explode(x))
+func flatten(xs, vs []any, depth float64) []any {
+ for _, v := range vs {
+ if vs, ok := v.([]any); ok && depth != 0 {
+ xs = flatten(xs, vs, depth-1)
+ } else {
+ xs = append(xs, v)
}
- return &expectedStringError{x}
- default:
- return &expectedArrayError{v}
}
+ return xs
}
type rangeIter struct {
- value, end, step interface{}
+ value, end, step any
}
-func (iter *rangeIter) Next() (interface{}, bool) {
+func (iter *rangeIter) Next() (any, bool) {
if compare(iter.step, 0)*compare(iter.value, iter.end) >= 0 {
return nil, false
}
@@ -971,7 +1130,7 @@ func (iter *rangeIter) Next() (interface{}, bool) {
return v, true
}
-func funcRange(_ interface{}, xs []interface{}) interface{} {
+func funcRange(_ any, xs []any) any {
for _, x := range xs {
switch x.(type) {
case int, float64, *big.Int:
@@ -982,43 +1141,59 @@ func funcRange(_ interface{}, xs []interface{}) interface{} {
return &rangeIter{xs[0], xs[1], xs[2]}
}
-func funcMinBy(v, x interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMin(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &expectedArrayError{v}
+ return &funcTypeError{"min", v}
}
- xs, ok := x.([]interface{})
+ return minMaxBy(vs, vs, true)
+}
+
+func funcMinBy(v, x any) any {
+ vs, ok := v.([]any)
+ if !ok {
+ return &funcTypeError{"min_by", v}
+ }
+ xs, ok := x.([]any)
if !ok {
- return &expectedArrayError{x}
+ return &funcTypeError{"min_by", x}
}
if len(vs) != len(xs) {
return &lengthMismatchError{"min_by", vs, xs}
}
- return funcMinMaxBy(vs, xs, true)
+ return minMaxBy(vs, xs, true)
}
-func funcMaxBy(v, x interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMax(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &expectedArrayError{v}
+ return &funcTypeError{"max", v}
+ }
+ return minMaxBy(vs, vs, false)
+}
+
+func funcMaxBy(v, x any) any {
+ vs, ok := v.([]any)
+ if !ok {
+ return &funcTypeError{"max_by", v}
}
- xs, ok := x.([]interface{})
+ xs, ok := x.([]any)
if !ok {
- return &expectedArrayError{x}
+ return &funcTypeError{"max_by", x}
}
if len(vs) != len(xs) {
return &lengthMismatchError{"max_by", vs, xs}
}
- return funcMinMaxBy(vs, xs, false)
+ return minMaxBy(vs, xs, false)
}
-func funcMinMaxBy(vs, xs []interface{}, isMin bool) interface{} {
+func minMaxBy(vs, xs []any, isMin bool) any {
if len(vs) == 0 {
return nil
}
i, j, x := 0, 0, xs[0]
for i++; i < len(xs); i++ {
- if (compare(x, xs[i]) > 0) == isMin {
+ if compare(x, xs[i]) > 0 == isMin {
j, x = i, xs[i]
}
}
@@ -1026,45 +1201,83 @@ func funcMinMaxBy(vs, xs []interface{}, isMin bool) interface{} {
}
type sortItem struct {
- value, key interface{}
+ value, key any
+}
+
+func sortItems(name string, v, x any) ([]*sortItem, error) {
+ vs, ok := v.([]any)
+ if !ok {
+ return nil, &funcTypeError{name, v}
+ }
+ xs, ok := x.([]any)
+ if !ok {
+ return nil, &funcTypeError{name, x}
+ }
+ if len(vs) != len(xs) {
+ return nil, &lengthMismatchError{name, vs, xs}
+ }
+ items := make([]*sortItem, len(vs))
+ for i, v := range vs {
+ items[i] = &sortItem{v, xs[i]}
+ }
+ sort.SliceStable(items, func(i, j int) bool {
+ return compare(items[i].key, items[j].key) < 0
+ })
+ return items, nil
+}
+
+func funcSort(v any) any {
+ return sortBy("sort", v, v)
}
-func funcSortBy(v, x interface{}) interface{} {
- items, err := sortItems("sort_by", v, x)
+func funcSortBy(v, x any) any {
+ return sortBy("sort_by", v, x)
+}
+
+func sortBy(name string, v, x any) any {
+ items, err := sortItems(name, v, x)
if err != nil {
return err
}
- rs := make([]interface{}, len(items))
+ rs := make([]any, len(items))
for i, x := range items {
rs[i] = x.value
}
return rs
}
-func funcGroupBy(v, x interface{}) interface{} {
+func funcGroupBy(v, x any) any {
items, err := sortItems("group_by", v, x)
if err != nil {
return err
}
- var rs []interface{}
- var last interface{}
+ var rs []any
+ var last any
for i, r := range items {
if i == 0 || compare(last, r.key) != 0 {
- rs, last = append(rs, []interface{}{r.value}), r.key
+ rs, last = append(rs, []any{r.value}), r.key
} else {
- rs[len(rs)-1] = append(rs[len(rs)-1].([]interface{}), r.value)
+ rs[len(rs)-1] = append(rs[len(rs)-1].([]any), r.value)
}
}
return rs
}
-func funcUniqueBy(v, x interface{}) interface{} {
- items, err := sortItems("unique_by", v, x)
+func funcUnique(v any) any {
+ return uniqueBy("unique", v, v)
+}
+
+func funcUniqueBy(v, x any) any {
+ return uniqueBy("unique_by", v, x)
+}
+
+func uniqueBy(name string, v, x any) any {
+ items, err := sortItems(name, v, x)
if err != nil {
return err
}
- var rs []interface{}
- var last interface{}
+ var rs []any
+ var last any
for i, r := range items {
if i == 0 || compare(last, r.key) != 0 {
rs, last = append(rs, r.value), r.key
@@ -1073,10 +1286,10 @@ func funcUniqueBy(v, x interface{}) interface{} {
return rs
}
-func funcJoin(v, x interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcJoin(v, x any) any {
+ vs, ok := values(v)
if !ok {
- return &expectedArrayError{v}
+ return &funcTypeError{"join", v}
}
if len(vs) == 0 {
return ""
@@ -1086,48 +1299,26 @@ func funcJoin(v, x interface{}) interface{} {
return &funcTypeError{"join", x}
}
ss := make([]string, len(vs))
- for i, e := range vs {
- switch e := e.(type) {
+ for i, v := range vs {
+ switch v := v.(type) {
case nil:
case string:
- ss[i] = e
+ ss[i] = v
case bool:
- if e {
+ if v {
ss[i] = "true"
} else {
ss[i] = "false"
}
case int, float64, *big.Int:
- ss[i] = jsonMarshal(e)
+ ss[i] = jsonMarshal(v)
default:
- return &unaryTypeError{"join", e}
+ return &joinTypeError{v}
}
}
return strings.Join(ss, sep)
}
-func sortItems(name string, v, x interface{}) ([]*sortItem, error) {
- vs, ok := v.([]interface{})
- if !ok {
- return nil, &expectedArrayError{v}
- }
- xs, ok := x.([]interface{})
- if !ok {
- return nil, &expectedArrayError{x}
- }
- if len(vs) != len(xs) {
- return nil, &lengthMismatchError{name, vs, xs}
- }
- items := make([]*sortItem, len(vs))
- for i, v := range vs {
- items[i] = &sortItem{v, xs[i]}
- }
- sort.SliceStable(items, func(i, j int) bool {
- return compare(items[i].key, items[j].key) < 0
- })
- return items, nil
-}
-
func funcSignificand(v float64) float64 {
if math.IsNaN(v) || math.IsInf(v, 0) || v == 0.0 {
return v
@@ -1139,22 +1330,22 @@ func funcExp10(v float64) float64 {
return math.Pow(10, v)
}
-func funcFrexp(v interface{}) interface{} {
+func funcFrexp(v any) any {
x, ok := toFloat(v)
if !ok {
return &funcTypeError{"frexp", v}
}
f, e := math.Frexp(x)
- return []interface{}{f, e}
+ return []any{f, e}
}
-func funcModf(v interface{}) interface{} {
+func funcModf(v any) any {
x, ok := toFloat(v)
if !ok {
return &funcTypeError{"modf", v}
}
i, f := math.Modf(x)
- return []interface{}{f, i}
+ return []any{f, i}
}
func funcLgamma(v float64) float64 {
@@ -1190,25 +1381,25 @@ func funcYn(l, r float64) float64 {
return math.Yn(int(l), r)
}
-func funcInfinite(interface{}) interface{} {
+func funcInfinite(any) any {
return math.Inf(1)
}
-func funcIsfinite(v interface{}) interface{} {
+func funcIsfinite(v any) any {
x, ok := toFloat(v)
return ok && !math.IsInf(x, 0)
}
-func funcIsinfinite(v interface{}) interface{} {
+func funcIsinfinite(v any) any {
x, ok := toFloat(v)
return ok && math.IsInf(x, 0)
}
-func funcNan(interface{}) interface{} {
+func funcNan(any) any {
return math.NaN()
}
-func funcIsnan(v interface{}) interface{} {
+func funcIsnan(v any) any {
x, ok := toFloat(v)
if !ok {
if v == nil {
@@ -1219,18 +1410,65 @@ func funcIsnan(v interface{}) interface{} {
return math.IsNaN(x)
}
-func funcIsnormal(v interface{}) interface{} {
- x, ok := toFloat(v)
- return ok && !math.IsNaN(x) && !math.IsInf(x, 0) && x != 0.0
+func funcIsnormal(v any) any {
+ if v, ok := toFloat(v); ok {
+ e := math.Float64bits(v) & 0x7ff0000000000000 >> 52
+ return 0 < e && e < 0x7ff
+ }
+ return false
+}
+
+// An `allocator` creates new maps and slices, stores the allocated addresses.
+// This allocator is used to reduce allocations on assignment operator (`=`),
+// update-assignment operator (`|=`), and the `map_values`, `del`, `delpaths`
+// functions.
+type allocator map[uintptr]struct{}
+
+func funcAllocator(any, []any) any {
+ return allocator{}
+}
+
+func (a allocator) allocated(v any) bool {
+ _, ok := a[reflect.ValueOf(v).Pointer()]
+ return ok
+}
+
+func (a allocator) makeObject(l int) map[string]any {
+ v := make(map[string]any, l)
+ if a != nil {
+ a[reflect.ValueOf(v).Pointer()] = struct{}{}
+ }
+ return v
+}
+
+func (a allocator) makeArray(l, c int) []any {
+ if c < l {
+ c = l
+ }
+ v := make([]any, l, c)
+ if a != nil {
+ a[reflect.ValueOf(v).Pointer()] = struct{}{}
+ }
+ return v
+}
+
+func funcSetpath(v, p, n any) any {
+ // There is no need to use an allocator on a single update.
+ return setpath(v, p, n, nil)
+}
+
+// Used in compiler#compileAssign and compiler#compileModify.
+func funcSetpathWithAllocator(v any, args []any) any {
+ return setpath(v, args[0], args[1], args[2].(allocator))
}
-func funcSetpath(v, p, w interface{}) interface{} {
- path, ok := p.([]interface{})
+func setpath(v, p, n any, a allocator) any {
+ path, ok := p.([]any)
if !ok {
return &funcTypeError{"setpath", p}
}
var err error
- if v, err = updatePaths(v, path, w, false); err != nil {
+ if v, err = update(v, path, n, a); err != nil {
if err, ok := err.(*funcTypeError); ok {
err.name = "setpath"
}
@@ -1239,188 +1477,74 @@ func funcSetpath(v, p, w interface{}) interface{} {
return v
}
-func funcDelpaths(v, p interface{}) interface{} {
- paths, ok := p.([]interface{})
+func funcDelpaths(v, p any) any {
+ return delpaths(v, p, allocator{})
+}
+
+// Used in compiler#compileAssign and compiler#compileModify.
+func funcDelpathsWithAllocator(v any, args []any) any {
+ return delpaths(v, args[0], args[1].(allocator))
+}
+
+func delpaths(v, p any, a allocator) any {
+ paths, ok := p.([]any)
if !ok {
return &funcTypeError{"delpaths", p}
}
+ if len(paths) == 0 {
+ return v
+ }
// Fills the paths with an empty value and then delete them. We cannot delete
// in each loop because array indices should not change. For example,
// jq -n "[0, 1, 2, 3] | delpaths([[1], [2]])" #=> [0, 3].
var empty struct{}
var err error
for _, p := range paths {
- path, ok := p.([]interface{})
+ path, ok := p.([]any)
if !ok {
return &funcTypeError{"delpaths", p}
}
- if v, err = updatePaths(v, path, empty, true); err != nil {
+ if v, err = update(v, path, empty, a); err != nil {
return err
}
}
return deleteEmpty(v)
}
-func updatePaths(v interface{}, path []interface{}, w interface{}, delpaths bool) (interface{}, error) {
+func update(v any, path []any, n any, a allocator) (any, error) {
if len(path) == 0 {
- return w, nil
+ return n, nil
}
- switch x := path[0].(type) {
+ switch p := path[0].(type) {
case string:
- if v == nil {
- if delpaths {
- return v, nil
- }
- v = make(map[string]interface{})
- }
- switch uu := v.(type) {
- case map[string]interface{}:
- if _, ok := uu[x]; !ok && delpaths {
- return v, nil
- }
- u, err := updatePaths(uu[x], path[1:], w, delpaths)
- if err != nil {
- return nil, err
- }
- vs := make(map[string]interface{}, len(uu))
- for k, v := range uu {
- vs[k] = v
- }
- vs[x] = u
- return vs, nil
+ switch v := v.(type) {
+ case nil:
+ return updateObject(nil, p, path[1:], n, a)
+ case map[string]any:
+ return updateObject(v, p, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedObjectError{v}
}
case int, float64, *big.Int:
- if v == nil {
- if delpaths {
- return v, nil
- }
- v = []interface{}{}
- }
- switch uu := v.(type) {
- case []interface{}:
- y, _ := toInt(x)
- l := len(uu)
- var copied bool
- if copied = y >= l; copied {
- if delpaths {
- return v, nil
- }
- if y > 0x3ffffff {
- return nil, &arrayIndexTooLargeError{y}
- }
- l = y + 1
- ys := make([]interface{}, l)
- copy(ys, uu)
- uu = ys
- } else if y < -l {
- if delpaths {
- return v, nil
- }
- return nil, &funcTypeError{v: y}
- } else if y < 0 {
- y += l
- }
- u, err := updatePaths(uu[y], path[1:], w, delpaths)
- if err != nil {
- return nil, err
- }
- if copied {
- uu[y] = u
- return uu, nil
- }
- vs := make([]interface{}, l)
- copy(vs, uu)
- vs[y] = u
- return vs, nil
+ i, _ := toInt(p)
+ switch v := v.(type) {
+ case nil:
+ return updateArrayIndex(nil, i, path[1:], n, a)
+ case []any:
+ return updateArrayIndex(v, i, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedArrayError{v}
}
- case map[string]interface{}:
- if len(x) == 0 {
- switch v.(type) {
- case []interface{}:
- return nil, &arrayIndexNotNumberError{x}
- default:
- return nil, &objectKeyNotStringError{x}
- }
- }
- if v == nil {
- v = []interface{}{}
- }
- switch uu := v.(type) {
- case []interface{}:
- var start, end int
- if x, ok := toInt(x["start"]); ok {
- x := toIndex(uu, x)
- if x > len(uu) || x == -1 {
- start = len(uu)
- } else if x == -2 {
- start = 0
- } else {
- start = x
- }
- }
- if x, ok := toInt(x["end"]); ok {
- x := toIndex(uu, x)
- if x == -1 {
- end = len(uu)
- } else if x < start {
- end = start
- } else {
- end = x
- }
- } else {
- end = len(uu)
- }
- if delpaths {
- if start >= end {
- return uu, nil
- }
- if len(path) > 1 {
- u, err := updatePaths(uu[start:end], path[1:], w, delpaths)
- if err != nil {
- return nil, err
- }
- switch us := u.(type) {
- case []interface{}:
- vs := make([]interface{}, len(uu))
- copy(vs, uu)
- copy(vs[start:end], us)
- return vs, nil
- default:
- return nil, &expectedArrayError{u}
- }
- }
- vs := make([]interface{}, len(uu))
- copy(vs, uu)
- for y := start; y < end; y++ {
- vs[y] = w
- }
- return vs, nil
- }
- if len(path) > 1 {
- u, err := updatePaths(uu[start:end], path[1:], w, delpaths)
- if err != nil {
- return nil, err
- }
- w = u
- }
- switch v := w.(type) {
- case []interface{}:
- vs := make([]interface{}, start+len(v)+len(uu)-end)
- copy(vs, uu[:start])
- copy(vs[start:], v)
- copy(vs[start+len(v):], uu[end:])
- return vs, nil
- default:
- return nil, &expectedArrayError{v}
- }
+ case map[string]any:
+ switch v := v.(type) {
+ case nil:
+ return updateArraySlice(nil, p, path[1:], n, a)
+ case []any:
+ return updateArraySlice(v, p, path[1:], n, a)
case struct{}:
return v, nil
default:
@@ -1428,47 +1552,192 @@ func updatePaths(v interface{}, path []interface{}, w interface{}, delpaths bool
}
default:
switch v.(type) {
- case []interface{}:
- return nil, &arrayIndexNotNumberError{x}
+ case []any:
+ return nil, &arrayIndexNotNumberError{p}
default:
- return nil, &objectKeyNotStringError{x}
+ return nil, &objectKeyNotStringError{p}
+ }
+ }
+}
+
+func updateObject(v map[string]any, k string, path []any, n any, a allocator) (any, error) {
+ x, ok := v[k]
+ if !ok && n == struct{}{} {
+ return v, nil
+ }
+ u, err := update(x, path, n, a)
+ if err != nil {
+ return nil, err
+ }
+ if a.allocated(v) {
+ v[k] = u
+ return v, nil
+ }
+ w := a.makeObject(len(v) + 1)
+ for k, v := range v {
+ w[k] = v
+ }
+ w[k] = u
+ return w, nil
+}
+
+func updateArrayIndex(v []any, i int, path []any, n any, a allocator) (any, error) {
+ var x any
+ if j := clampIndex(i, -1, len(v)); j < 0 {
+ if n == struct{}{} {
+ return v, nil
+ }
+ return nil, &funcTypeError{v: i}
+ } else if j < len(v) {
+ i = j
+ x = v[i]
+ } else {
+ if n == struct{}{} {
+ return v, nil
}
+ if i >= 0x8000000 {
+ return nil, &arrayIndexTooLargeError{i}
+ }
+ }
+ u, err := update(x, path, n, a)
+ if err != nil {
+ return nil, err
+ }
+ l, c := len(v), cap(v)
+ if a.allocated(v) {
+ if i < c {
+ if i >= l {
+ v = v[:i+1]
+ }
+ v[i] = u
+ return v, nil
+ }
+ c *= 2
+ }
+ if i >= l {
+ l = i + 1
+ }
+ w := a.makeArray(l, c)
+ copy(w, v)
+ w[i] = u
+ return w, nil
+}
+
+func updateArraySlice(v []any, m map[string]any, path []any, n any, a allocator) (any, error) {
+ s, ok := m["start"]
+ if !ok {
+ return nil, &expectedStartEndError{m}
+ }
+ e, ok := m["end"]
+ if !ok {
+ return nil, &expectedStartEndError{m}
+ }
+ var start, end int
+ if i, ok := toInt(s); ok {
+ start = clampIndex(i, 0, len(v))
+ }
+ if i, ok := toInt(e); ok {
+ end = clampIndex(i, start, len(v))
+ } else {
+ end = len(v)
+ }
+ if start == end && n == struct{}{} {
+ return v, nil
+ }
+ u, err := update(v[start:end], path, n, a)
+ if err != nil {
+ return nil, err
+ }
+ switch u := u.(type) {
+ case []any:
+ var w []any
+ if len(u) == end-start && a.allocated(v) {
+ w = v
+ } else {
+ w = a.makeArray(len(v)-(end-start)+len(u), 0)
+ copy(w, v[:start])
+ copy(w[start+len(u):], v[end:])
+ }
+ copy(w[start:], u)
+ return w, nil
+ case struct{}:
+ var w []any
+ if a.allocated(v) {
+ w = v
+ } else {
+ w = a.makeArray(len(v), 0)
+ copy(w, v)
+ }
+ for i := start; i < end; i++ {
+ w[i] = u
+ }
+ return w, nil
+ default:
+ return nil, &expectedArrayError{u}
+ }
+}
+
+func deleteEmpty(v any) any {
+ switch v := v.(type) {
+ case struct{}:
+ return nil
+ case map[string]any:
+ for k, w := range v {
+ if w == struct{}{} {
+ delete(v, k)
+ } else {
+ v[k] = deleteEmpty(w)
+ }
+ }
+ return v
+ case []any:
+ var j int
+ for _, w := range v {
+ if w != struct{}{} {
+ v[j] = deleteEmpty(w)
+ j++
+ }
+ }
+ for i := j; i < len(v); i++ {
+ v[i] = nil
+ }
+ return v[:j]
+ default:
+ return v
}
}
-func funcGetpath(v, p interface{}) interface{} {
- keys, ok := p.([]interface{})
+func funcGetpath(v, p any) any {
+ keys, ok := p.([]any)
if !ok {
return &funcTypeError{"getpath", p}
}
u := v
for _, x := range keys {
switch v.(type) {
- case map[string]interface{}:
- case []interface{}:
- case nil:
+ case nil, []any, map[string]any:
+ v = funcIndex2(nil, v, x)
+ if _, ok := v.(error); ok {
+ return &getpathError{u, p}
+ }
default:
return &getpathError{u, p}
}
- v = funcIndex(nil, v, x)
- if _, ok := v.(error); ok {
- return &getpathError{u, p}
- }
}
return v
}
-func funcTranspose(v interface{}) interface{} {
- vss, ok := v.([]interface{})
+func funcTranspose(v any) any {
+ vss, ok := v.([]any)
if !ok {
return &funcTypeError{"transpose", v}
}
if len(vss) == 0 {
- return []interface{}{}
+ return []any{}
}
var l int
for _, vs := range vss {
- vs, ok := vs.([]interface{})
+ vs, ok := vs.([]any)
if !ok {
return &funcTypeError{"transpose", v}
}
@@ -1476,23 +1745,23 @@ func funcTranspose(v interface{}) interface{} {
l = k
}
}
- wss := make([][]interface{}, l)
- xs := make([]interface{}, l)
+ wss := make([][]any, l)
+ xs := make([]any, l)
for i, k := 0, len(vss); i < l; i++ {
- s := make([]interface{}, k)
+ s := make([]any, k)
wss[i] = s
xs[i] = s
}
for i, vs := range vss {
- for j, v := range vs.([]interface{}) {
+ for j, v := range vs.([]any) {
wss[j][i] = v
}
}
return xs
}
-func funcBsearch(v, t interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcBsearch(v, t any) any {
+ vs, ok := v.([]any)
if !ok {
return &funcTypeError{"bsearch", v}
}
@@ -1505,23 +1774,23 @@ func funcBsearch(v, t interface{}) interface{} {
return -i - 1
}
-func funcGmtime(v interface{}) interface{} {
+func funcGmtime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.UTC)
}
return &funcTypeError{"gmtime", v}
}
-func funcLocaltime(v interface{}) interface{} {
+func funcLocaltime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.Local)
}
return &funcTypeError{"localtime", v}
}
-func epochToArray(v float64, loc *time.Location) []interface{} {
+func epochToArray(v float64, loc *time.Location) []any {
t := time.Unix(int64(v), int64((v-math.Floor(v))*1e9)).In(loc)
- return []interface{}{
+ return []any{
t.Year(),
int(t.Month()) - 1,
t.Day(),
@@ -1533,22 +1802,26 @@ func epochToArray(v float64, loc *time.Location) []interface{} {
}
}
-func funcMktime(v interface{}) interface{} {
- if a, ok := v.([]interface{}); ok {
+func funcMktime(v any) any {
+ if a, ok := v.([]any); ok {
t, err := arrayToTime("mktime", a, time.UTC)
if err != nil {
return err
}
- return float64(t.Unix())
+ return timeToEpoch(t)
}
return &funcTypeError{"mktime", v}
}
-func funcStrftime(v, x interface{}) interface{} {
+func timeToEpoch(t time.Time) float64 {
+ return float64(t.Unix()) + float64(t.Nanosecond())/1e9
+}
+
+func funcStrftime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.UTC)
}
- if a, ok := v.([]interface{}); ok {
+ if a, ok := v.([]any); ok {
if format, ok := x.(string); ok {
t, err := arrayToTime("strftime", a, time.UTC)
if err != nil {
@@ -1561,11 +1834,11 @@ func funcStrftime(v, x interface{}) interface{} {
return &funcTypeError{"strftime", v}
}
-func funcStrflocaltime(v, x interface{}) interface{} {
+func funcStrflocaltime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.Local)
}
- if a, ok := v.([]interface{}); ok {
+ if a, ok := v.([]any); ok {
if format, ok := x.(string); ok {
t, err := arrayToTime("strflocaltime", a, time.Local)
if err != nil {
@@ -1578,7 +1851,7 @@ func funcStrflocaltime(v, x interface{}) interface{} {
return &funcTypeError{"strflocaltime", v}
}
-func funcStrptime(v, x interface{}) interface{} {
+func funcStrptime(v, x any) any {
if v, ok := v.(string); ok {
if format, ok := x.(string); ok {
t, err := timefmt.Parse(v, format)
@@ -1589,14 +1862,14 @@ func funcStrptime(v, x interface{}) interface{} {
if t == s {
return &funcTypeError{"strptime", v}
}
- return epochToArray(float64(t.Unix())+float64(t.Nanosecond())/1e9, time.UTC)
+ return epochToArray(timeToEpoch(t), time.UTC)
}
return &funcTypeError{"strptime", x}
}
return &funcTypeError{"strptime", v}
}
-func arrayToTime(name string, a []interface{}, loc *time.Location) (time.Time, error) {
+func arrayToTime(name string, a []any, loc *time.Location) (time.Time, error) {
var t time.Time
if len(a) != 8 {
return t, &funcTypeError{name, a}
@@ -1636,12 +1909,11 @@ func arrayToTime(name string, a []interface{}, loc *time.Location) (time.Time, e
return time.Date(y, time.Month(m), d, h, min, sec, nsec, loc), nil
}
-func funcNow(interface{}) interface{} {
- t := time.Now()
- return float64(t.Unix()) + float64(t.Nanosecond())/1e9
+func funcNow(any) any {
+ return timeToEpoch(time.Now())
}
-func funcMatch(v, re, fs, testing interface{}) interface{} {
+func funcMatch(v, re, fs, testing any) any {
var flags string
if fs != nil {
v, ok := fs.(string)
@@ -1674,16 +1946,16 @@ func funcMatch(v, re, fs, testing interface{}) interface{} {
xs = [][]int{got}
}
}
- res, names := make([]interface{}, len(xs)), r.SubexpNames()
+ res, names := make([]any, len(xs)), r.SubexpNames()
for i, x := range xs {
- captures := make([]interface{}, (len(x)-2)/2)
+ captures := make([]any, (len(x)-2)/2)
for j := 1; j < len(x)/2; j++ {
- var name interface{}
+ var name any
if n := names[j]; n != "" {
name = n
}
if x[j*2] < 0 {
- captures[j-1] = map[string]interface{}{
+ captures[j-1] = map[string]any{
"name": name,
"offset": -1,
"length": 0,
@@ -1691,14 +1963,14 @@ func funcMatch(v, re, fs, testing interface{}) interface{} {
}
continue
}
- captures[j-1] = map[string]interface{}{
+ captures[j-1] = map[string]any{
"name": name,
"offset": len([]rune(s[:x[j*2]])),
"length": len([]rune(s[:x[j*2+1]])) - len([]rune(s[:x[j*2]])),
"string": s[x[j*2]:x[j*2+1]],
}
}
- res[i] = map[string]interface{}{
+ res[i] = map[string]any{
"offset": len([]rune(s[:x[0]])),
"length": len([]rune(s[:x[1]])) - len([]rune(s[:x[0]])),
"string": s[x[0]:x[1]],
@@ -1728,7 +2000,28 @@ func compileRegexp(re, flags string) (*regexp.Regexp, error) {
return r, nil
}
-func funcError(v interface{}, args []interface{}) interface{} {
+func funcCapture(v any) any {
+ vs, ok := v.(map[string]any)
+ if !ok {
+ return &expectedObjectError{v}
+ }
+ v = vs["captures"]
+ captures, ok := v.([]any)
+ if !ok {
+ return &expectedArrayError{v}
+ }
+ w := make(map[string]any, len(captures))
+ for _, capture := range captures {
+ if capture, ok := capture.(map[string]any); ok {
+ if name, ok := capture["name"].(string); ok {
+ w[name] = capture["string"]
+ }
+ }
+ }
+ return w
+}
+
+func funcError(v any, args []any) any {
if len(args) > 0 {
v = args[0]
}
@@ -1739,11 +2032,11 @@ func funcError(v interface{}, args []interface{}) interface{} {
return &exitCodeError{v, code, false}
}
-func funcHalt(interface{}) interface{} {
+func funcHalt(any) any {
return &exitCodeError{nil, 0, true}
}
-func funcHaltError(v interface{}, args []interface{}) interface{} {
+func funcHaltError(v any, args []any) any {
code := 5
if len(args) > 0 {
var ok bool
@@ -1754,14 +2047,7 @@ func funcHaltError(v interface{}, args []interface{}) interface{} {
return &exitCodeError{v, code, true}
}
-func internalfuncTypeError(v, x interface{}) interface{} {
- if x, ok := x.(string); ok {
- return &funcTypeError{x, v}
- }
- return &funcTypeError{"_type_error", v}
-}
-
-func toInt(x interface{}) (int, bool) {
+func toInt(x any) (int, bool) {
switch x := x.(type) {
case int:
return x, true
@@ -1769,30 +2055,30 @@ func toInt(x interface{}) (int, bool) {
return floatToInt(x), true
case *big.Int:
if x.IsInt64() {
- if i := x.Int64(); minInt <= i && i <= maxInt {
+ if i := x.Int64(); math.MinInt <= i && i <= math.MaxInt {
return int(i), true
}
}
if x.Sign() > 0 {
- return maxInt, true
+ return math.MaxInt, true
}
- return minInt, true
+ return math.MinInt, true
default:
return 0, false
}
}
func floatToInt(x float64) int {
- if minInt <= x && x <= maxInt {
+ if math.MinInt <= x && x <= math.MaxInt {
return int(x)
}
if x > 0 {
- return maxInt
+ return math.MaxInt
}
- return minInt
+ return math.MinInt
}
-func toFloat(x interface{}) (float64, bool) {
+func toFloat(x any) (float64, bool) {
switch x := x.(type) {
case int:
return float64(x), true
diff --git a/vendor/github.com/itchyny/gojq/go.dev.mod b/vendor/github.com/itchyny/gojq/go.dev.mod
index 46e652e2..9a0579ca 100644
--- a/vendor/github.com/itchyny/gojq/go.dev.mod
+++ b/vendor/github.com/itchyny/gojq/go.dev.mod
@@ -1,8 +1,8 @@
module github.com/itchyny/gojq
-go 1.16
+go 1.18
require (
github.com/itchyny/astgen-go v0.0.0-20210914105503-cc8fccf6f972 // indirect
- github.com/itchyny/timefmt-go v0.1.3 // indirect
+ github.com/itchyny/timefmt-go v0.1.5 // indirect
)
diff --git a/vendor/github.com/itchyny/gojq/go.dev.sum b/vendor/github.com/itchyny/gojq/go.dev.sum
index 467aa0b9..66aee6c5 100644
--- a/vendor/github.com/itchyny/gojq/go.dev.sum
+++ b/vendor/github.com/itchyny/gojq/go.dev.sum
@@ -1,4 +1,4 @@
github.com/itchyny/astgen-go v0.0.0-20210914105503-cc8fccf6f972 h1:XYWolmPDLTY9B1O5o/Ad811/mtVkaHWMiZdbPLm/nDA=
github.com/itchyny/astgen-go v0.0.0-20210914105503-cc8fccf6f972/go.mod h1:jTXcxGeQMJfFN3wWjtzb4aAaWDDN+QbezE0HjH1XfNk=
-github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU=
-github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
+github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
+github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
diff --git a/vendor/github.com/itchyny/gojq/gojq.go b/vendor/github.com/itchyny/gojq/gojq.go
index 8f53b356..e078c809 100644
--- a/vendor/github.com/itchyny/gojq/gojq.go
+++ b/vendor/github.com/itchyny/gojq/gojq.go
@@ -1,5 +1,5 @@
-// Package gojq provides the parser and interpreter of gojq.
+// Package gojq provides the parser and the interpreter of gojq.
+// Please refer to [Usage as a library] for introduction.
//
-// Please refer to https://github.com/itchyny/gojq#usage-as-a-library for
-// introduction of the usage as a library.
+// [Usage as a library]: https://github.com/itchyny/gojq#usage-as-a-library
package gojq
diff --git a/vendor/github.com/itchyny/gojq/iter.go b/vendor/github.com/itchyny/gojq/iter.go
index 0cee25ba..d0bed960 100644
--- a/vendor/github.com/itchyny/gojq/iter.go
+++ b/vendor/github.com/itchyny/gojq/iter.go
@@ -2,11 +2,11 @@ package gojq
// Iter is an interface for an iterator.
type Iter interface {
- Next() (interface{}, bool)
+ Next() (any, bool)
}
-// NewIter creates a new Iter from values.
-func NewIter(values ...interface{}) Iter {
+// NewIter creates a new [Iter] from values.
+func NewIter(values ...any) Iter {
switch len(values) {
case 0:
return emptyIter{}
@@ -20,16 +20,16 @@ func NewIter(values ...interface{}) Iter {
type emptyIter struct{}
-func (emptyIter) Next() (interface{}, bool) {
+func (emptyIter) Next() (any, bool) {
return nil, false
}
type unitIter struct {
- value interface{}
+ value any
done bool
}
-func (iter *unitIter) Next() (interface{}, bool) {
+func (iter *unitIter) Next() (any, bool) {
if iter.done {
return nil, false
}
@@ -37,9 +37,9 @@ func (iter *unitIter) Next() (interface{}, bool) {
return iter.value, true
}
-type sliceIter []interface{}
+type sliceIter []any
-func (iter *sliceIter) Next() (interface{}, bool) {
+func (iter *sliceIter) Next() (any, bool) {
if len(*iter) == 0 {
return nil, false
}
diff --git a/vendor/github.com/itchyny/gojq/lexer.go b/vendor/github.com/itchyny/gojq/lexer.go
index d36a6838..82bb2b6b 100644
--- a/vendor/github.com/itchyny/gojq/lexer.go
+++ b/vendor/github.com/itchyny/gojq/lexer.go
@@ -1,8 +1,7 @@
package gojq
import (
- "strconv"
- "strings"
+ "encoding/json"
"unicode/utf8"
)
@@ -235,9 +234,9 @@ func (l *lexer) Lex(lval *yySymType) (tokenType int) {
return tok
default:
if ch >= utf8.RuneSelf {
- r, _ := utf8.DecodeRuneInString(l.source[l.offset-1:])
+ r, size := utf8.DecodeRuneInString(l.source[l.offset-1:])
+ l.offset += size
l.token = string(r)
- l.offset += len(l.token)
}
}
return int(ch)
@@ -381,82 +380,129 @@ func (l *lexer) validNumber() bool {
}
func (l *lexer) scanString(start int) (int, string) {
- var quote, newline bool
+ var decode bool
+ var controls int
unquote := func(src string, quote bool) (string, error) {
- if quote {
- src = "\"" + src + "\""
+ if !decode {
+ if quote {
+ return src, nil
+ }
+ return src[1 : len(src)-1], nil
}
- if newline {
- src = strings.ReplaceAll(src, "\n", "\\n")
+ var buf []byte
+ if !quote && controls == 0 {
+ buf = []byte(src)
+ } else {
+ buf = quoteAndEscape(src, quote, controls)
}
- return strconv.Unquote(src)
+ if err := json.Unmarshal(buf, &src); err != nil {
+ return "", err
+ }
+ return src, nil
}
- for i, m := l.offset, len(l.source); i < m; i++ {
+ for i := l.offset; i < len(l.source); i++ {
ch := l.source[i]
switch ch {
case '\\':
- quote = !quote
- case '\n':
- newline = true
- case '"':
- if !quote {
- if !l.inString {
- l.offset = i + 1
- l.token = l.source[start:l.offset]
- str, err := unquote(l.token, false)
- if err != nil {
- return tokInvalid, ""
+ if i++; i >= len(l.source) {
+ break
+ }
+ switch l.source[i] {
+ case 'u':
+ for j := 1; j <= 4; j++ {
+ if i+j >= len(l.source) || !isHex(l.source[i+j]) {
+ l.offset = i + j
+ l.token = l.source[i-1 : l.offset]
+ return tokInvalidEscapeSequence, ""
}
- return tokString, str
}
- if i > l.offset {
- l.offset = i
- l.token = l.source[start:l.offset]
- str, err := unquote(l.token, true)
- if err != nil {
- return tokInvalid, ""
- }
- return tokString, str
+ i += 4
+ fallthrough
+ case '"', '/', '\\', 'b', 'f', 'n', 'r', 't':
+ decode = true
+ case '(':
+ if !l.inString {
+ l.inString = true
+ return tokStringStart, ""
}
- l.inString = false
- l.offset = i + 1
- return tokStringEnd, ""
- }
- quote = false
- case '(':
- if quote {
- if l.inString {
- if i > l.offset+1 {
- l.offset = i - 1
- l.token = l.source[start:l.offset]
- str, err := unquote(l.token, true)
- if err != nil {
- return tokInvalid, ""
- }
- return tokString, str
- }
- l.offset = i + 1
+ if i == l.offset+1 {
+ l.offset += 2
l.inString = false
return tokStringQuery, ""
}
- l.inString = true
- return tokStringStart, ""
+ l.offset = i - 1
+ l.token = l.source[start:l.offset]
+ str, err := unquote(l.token, true)
+ if err != nil {
+ return tokInvalid, ""
+ }
+ return tokString, str
+ default:
+ l.offset = i + 1
+ l.token = l.source[l.offset-2 : l.offset]
+ return tokInvalidEscapeSequence, ""
}
- default:
- if quote {
- if !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
- '0' <= ch && ch <= '9' || ch == '\'' || ch == '"') {
- l.offset = i + 1
- l.token = l.source[l.offset-2 : l.offset]
+ case '"':
+ if !l.inString {
+ l.offset = i + 1
+ l.token = l.source[start:l.offset]
+ str, err := unquote(l.token, false)
+ if err != nil {
return tokInvalid, ""
}
- quote = false
+ return tokString, str
+ }
+ if i > l.offset {
+ l.offset = i
+ l.token = l.source[start:l.offset]
+ str, err := unquote(l.token, true)
+ if err != nil {
+ return tokInvalid, ""
+ }
+ return tokString, str
+ }
+ l.inString = false
+ l.offset = i + 1
+ return tokStringEnd, ""
+ default:
+ if !decode {
+ decode = ch > '~'
+ }
+ if ch < ' ' { // ref: unquoteBytes in encoding/json
+ controls++
}
}
}
l.offset = len(l.source)
- l.token = l.source[start:l.offset]
- return tokInvalid, ""
+ l.token = ""
+ return tokUnterminatedString, ""
+}
+
+func quoteAndEscape(src string, quote bool, controls int) []byte {
+ size := len(src) + controls*5
+ if quote {
+ size += 2
+ }
+ buf := make([]byte, size)
+ var j int
+ if quote {
+ buf[0] = '"'
+ buf[len(buf)-1] = '"'
+ j++
+ }
+ for i := 0; i < len(src); i++ {
+ if ch := src[i]; ch < ' ' {
+ const hex = "0123456789abcdef"
+ copy(buf[j:], `\u00`)
+ buf[j+4] = hex[ch>>4]
+ buf[j+5] = hex[ch&0xF]
+ j += 6
+ } else {
+ buf[j] = ch
+ j++
+ }
+ }
+ return buf
}
type parseError struct {
@@ -466,24 +512,18 @@ type parseError struct {
}
func (err *parseError) Error() string {
- var message string
- prefix := "unexpected"
- switch {
- case err.tokenType == eof:
- message = ""
- case err.tokenType == tokInvalid:
- prefix = "invalid"
- fallthrough
- case err.tokenType >= utf8.RuneSelf:
- if strings.HasPrefix(err.token, "\"") {
- message = err.token
- } else {
- message = "\"" + err.token + "\""
- }
+ switch err.tokenType {
+ case eof:
+ return "unexpected EOF"
+ case tokInvalid:
+ return "invalid token " + jsonMarshal(err.token)
+ case tokInvalidEscapeSequence:
+ return `invalid escape sequence "` + err.token + `" in string literal`
+ case tokUnterminatedString:
+ return "unterminated string literal"
default:
- message = strconv.Quote(string(rune(err.tokenType)))
+ return "unexpected token " + jsonMarshal(err.token)
}
- return prefix + " token " + message
}
func (err *parseError) Token() (string, int) {
@@ -492,12 +532,7 @@ func (err *parseError) Token() (string, int) {
func (l *lexer) Error(string) {
offset, token := l.offset, l.token
- switch {
- case l.tokenType == eof:
- offset++
- case l.tokenType >= utf8.RuneSelf:
- offset -= len(token) - 1
- default:
+ if l.tokenType != eof && l.tokenType < utf8.RuneSelf {
token = string(rune(l.tokenType))
}
l.err = &parseError{offset, token, l.tokenType}
@@ -518,6 +553,12 @@ func isIdent(ch byte, tail bool) bool {
tail && isNumber(ch)
}
+func isHex(ch byte) bool {
+ return 'a' <= ch && ch <= 'f' ||
+ 'A' <= ch && ch <= 'F' ||
+ isNumber(ch)
+}
+
func isNumber(ch byte) bool {
return '0' <= ch && ch <= '9'
}
diff --git a/vendor/github.com/itchyny/gojq/math.go b/vendor/github.com/itchyny/gojq/math.go
deleted file mode 100644
index 55d64765..00000000
--- a/vendor/github.com/itchyny/gojq/math.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package gojq
-
-import "math/bits"
-
-const (
- maxInt = 1<<(bits.UintSize-1) - 1 // math.MaxInt64 or math.MaxInt32
- minInt = -maxInt - 1 // math.MinInt64 or math.MinInt32
- maxHalfInt = 1<<(bits.UintSize/2-1) - 1 // math.MaxInt32 or math.MaxInt16
- minHalfInt = -maxHalfInt - 1 // math.MinInt32 or math.MinInt16
-)
diff --git a/vendor/github.com/itchyny/gojq/module_loader.go b/vendor/github.com/itchyny/gojq/module_loader.go
index b6cebca9..6e9ba48c 100644
--- a/vendor/github.com/itchyny/gojq/module_loader.go
+++ b/vendor/github.com/itchyny/gojq/module_loader.go
@@ -9,15 +9,26 @@ import (
"strings"
)
-type moduleLoader struct {
- paths []string
-}
+// ModuleLoader is the interface for loading modules.
+//
+// Implement following optional methods. Use [NewModuleLoader] to load local modules.
+//
+// LoadModule(string) (*Query, error)
+// LoadModuleWithMeta(string, map[string]any) (*Query, error)
+// LoadInitModules() ([]*Query, error)
+// LoadJSON(string) (any, error)
+// LoadJSONWithMeta(string, map[string]any) (any, error)
+type ModuleLoader any
-// NewModuleLoader creates a new ModuleLoader reading local modules in the paths.
+// NewModuleLoader creates a new [ModuleLoader] reading local modules in the paths.
func NewModuleLoader(paths []string) ModuleLoader {
return &moduleLoader{expandHomeDir(paths)}
}
+type moduleLoader struct {
+ paths []string
+}
+
func (l *moduleLoader) LoadInitModules() ([]*Query, error) {
var qs []*Query
for _, path := range l.paths {
@@ -40,14 +51,14 @@ func (l *moduleLoader) LoadInitModules() ([]*Query, error) {
}
q, err := parseModule(path, string(cnt))
if err != nil {
- return nil, &queryParseError{"query in module", path, string(cnt), err}
+ return nil, &queryParseError{path, string(cnt), err}
}
qs = append(qs, q)
}
return qs, nil
}
-func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]interface{}) (*Query, error) {
+func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]any) (*Query, error) {
path, err := l.lookupModule(name, ".jq", meta)
if err != nil {
return nil, err
@@ -58,12 +69,12 @@ func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]interface
}
q, err := parseModule(path, string(cnt))
if err != nil {
- return nil, &queryParseError{"query in module", path, string(cnt), err}
+ return nil, &queryParseError{path, string(cnt), err}
}
return q, nil
}
-func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}) (interface{}, error) {
+func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]any) (any, error) {
path, err := l.lookupModule(name, ".json", meta)
if err != nil {
return nil, err
@@ -73,11 +84,11 @@ func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}
return nil, err
}
defer f.Close()
- var vals []interface{}
+ var vals []any
dec := json.NewDecoder(f)
dec.UseNumber()
for {
- var val interface{}
+ var val any
if err := dec.Decode(&val); err != nil {
if err == io.EOF {
break
@@ -96,7 +107,7 @@ func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}
return vals, nil
}
-func (l *moduleLoader) lookupModule(name, extension string, meta map[string]interface{}) (string, error) {
+func (l *moduleLoader) lookupModule(name, extension string, meta map[string]any) (string, error) {
paths := l.paths
if path := searchPath(meta); path != "" {
paths = append([]string{path}, paths...)
@@ -135,7 +146,7 @@ func parseModule(path, cnt string) (*Query, error) {
return q, nil
}
-func searchPath(meta map[string]interface{}) string {
+func searchPath(meta map[string]any) string {
x, ok := meta["search"]
if !ok {
return ""
diff --git a/vendor/github.com/itchyny/gojq/normalize.go b/vendor/github.com/itchyny/gojq/normalize.go
index afca122b..2bfcd215 100644
--- a/vendor/github.com/itchyny/gojq/normalize.go
+++ b/vendor/github.com/itchyny/gojq/normalize.go
@@ -7,8 +7,8 @@ import (
"strings"
)
-func normalizeNumber(v json.Number) interface{} {
- if i, err := v.Int64(); err == nil && minInt <= i && i <= maxInt {
+func normalizeNumber(v json.Number) any {
+ if i, err := v.Int64(); err == nil && math.MinInt <= i && i <= math.MaxInt {
return int(i)
}
if strings.ContainsAny(v.String(), ".eE") {
@@ -25,22 +25,22 @@ func normalizeNumber(v json.Number) interface{} {
return math.Inf(1)
}
-func normalizeNumbers(v interface{}) interface{} {
+func normalizeNumbers(v any) any {
switch v := v.(type) {
case json.Number:
return normalizeNumber(v)
case *big.Int:
if v.IsInt64() {
- if i := v.Int64(); minInt <= i && i <= maxInt {
+ if i := v.Int64(); math.MinInt <= i && i <= math.MaxInt {
return int(i)
}
}
return v
case int64:
- if v > maxInt || v < minInt {
- return new(big.Int).SetInt64(v)
+ if math.MinInt <= v && v <= math.MaxInt {
+ return int(v)
}
- return int(v)
+ return big.NewInt(v)
case int32:
return int(v)
case int16:
@@ -48,68 +48,36 @@ func normalizeNumbers(v interface{}) interface{} {
case int8:
return int(v)
case uint:
- if v > maxInt {
- return new(big.Int).SetUint64(uint64(v))
+ if v <= math.MaxInt {
+ return int(v)
}
- return int(v)
+ return new(big.Int).SetUint64(uint64(v))
case uint64:
- if v > maxInt {
- return new(big.Int).SetUint64(v)
+ if v <= math.MaxInt {
+ return int(v)
}
- return int(v)
+ return new(big.Int).SetUint64(v)
case uint32:
- if uint64(v) > maxInt {
- return new(big.Int).SetUint64(uint64(v))
+ if uint64(v) <= math.MaxInt {
+ return int(v)
}
- return int(v)
+ return new(big.Int).SetUint64(uint64(v))
case uint16:
return int(v)
case uint8:
return int(v)
case float32:
return float64(v)
- case map[string]interface{}:
- for k, x := range v {
- v[k] = normalizeNumbers(x)
- }
- return v
- case []interface{}:
+ case []any:
for i, x := range v {
v[i] = normalizeNumbers(x)
}
return v
- default:
- return v
- }
-}
-
-// It's ok to delete destructively because this function is used right after
-// updatePaths, where it shallow-copies maps or slices on updates.
-func deleteEmpty(v interface{}) interface{} {
- switch v := v.(type) {
- case struct{}:
- return nil
- case map[string]interface{}:
- for k, w := range v {
- if w == struct{}{} {
- delete(v, k)
- } else {
- v[k] = deleteEmpty(w)
- }
+ case map[string]any:
+ for k, x := range v {
+ v[k] = normalizeNumbers(x)
}
return v
- case []interface{}:
- var j int
- for _, w := range v {
- if w != struct{}{} {
- v[j] = deleteEmpty(w)
- j++
- }
- }
- for i := j; i < len(v); i++ {
- v[i] = nil
- }
- return v[:j]
default:
return v
}
diff --git a/vendor/github.com/itchyny/gojq/operator.go b/vendor/github.com/itchyny/gojq/operator.go
index 80e13ef9..73a548e0 100644
--- a/vendor/github.com/itchyny/gojq/operator.go
+++ b/vendor/github.com/itchyny/gojq/operator.go
@@ -37,7 +37,7 @@ const (
OpUpdateAlt
)
-// String implements Stringer.
+// String implements [fmt.Stringer].
func (op Operator) String() string {
switch op {
case OpPipe:
@@ -93,7 +93,7 @@ func (op Operator) String() string {
}
}
-// GoString implements GoStringer.
+// GoString implements [fmt.GoStringer].
func (op Operator) GoString() (str string) {
defer func() { str = "gojq." + str }()
switch op {
@@ -208,23 +208,19 @@ func (op Operator) getFunc() string {
}
func binopTypeSwitch(
- l, r interface{},
- callbackInts func(_, _ int) interface{},
- callbackFloats func(_, _ float64) interface{},
- callbackBigInts func(_, _ *big.Int) interface{},
- callbackStrings func(_, _ string) interface{},
- callbackArrays func(_, _ []interface{}) interface{},
- callbackMaps func(_, _ map[string]interface{}) interface{},
- fallback func(_, _ interface{}) interface{}) interface{} {
+ l, r any,
+ callbackInts func(_, _ int) any,
+ callbackFloats func(_, _ float64) any,
+ callbackBigInts func(_, _ *big.Int) any,
+ callbackStrings func(_, _ string) any,
+ callbackArrays func(_, _ []any) any,
+ callbackMaps func(_, _ map[string]any) any,
+ fallback func(_, _ any) any) any {
switch l := l.(type) {
case int:
switch r := r.(type) {
case int:
- if minHalfInt <= l && l <= maxHalfInt &&
- minHalfInt <= r && r <= maxHalfInt {
- return callbackInts(l, r)
- }
- return callbackBigInts(big.NewInt(int64(l)), big.NewInt(int64(r)))
+ return callbackInts(l, r)
case float64:
return callbackFloats(float64(l), r)
case *big.Int:
@@ -261,16 +257,16 @@ func binopTypeSwitch(
default:
return fallback(l, r)
}
- case []interface{}:
+ case []any:
switch r := r.(type) {
- case []interface{}:
+ case []any:
return callbackArrays(l, r)
default:
return fallback(l, r)
}
- case map[string]interface{}:
+ case map[string]any:
switch r := r.(type) {
- case map[string]interface{}:
+ case map[string]any:
return callbackMaps(l, r)
default:
return fallback(l, r)
@@ -280,7 +276,7 @@ func binopTypeSwitch(
}
}
-func funcOpPlus(v interface{}) interface{} {
+func funcOpPlus(v any) any {
switch v := v.(type) {
case int:
return v
@@ -293,7 +289,7 @@ func funcOpPlus(v interface{}) interface{} {
}
}
-func funcOpNegate(v interface{}) interface{} {
+func funcOpNegate(v any) any {
switch v := v.(type) {
case int:
return -v
@@ -306,28 +302,38 @@ func funcOpNegate(v interface{}) interface{} {
}
}
-func funcOpAdd(_, l, r interface{}) interface{} {
- if l == nil {
- return r
- } else if r == nil {
- return l
- }
+func funcOpAdd(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} { return l + r },
- func(l, r float64) interface{} { return l + r },
- func(l, r *big.Int) interface{} { return new(big.Int).Add(l, r) },
- func(l, r string) interface{} { return l + r },
- func(l, r []interface{}) interface{} {
+ func(l, r int) any {
+ if v := l + r; (v >= l) == (r >= 0) {
+ return v
+ }
+ x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+ return x.Add(x, y)
+ },
+ func(l, r float64) any { return l + r },
+ func(l, r *big.Int) any { return new(big.Int).Add(l, r) },
+ func(l, r string) any { return l + r },
+ func(l, r []any) any {
+ if len(l) == 0 {
+ return r
+ }
if len(r) == 0 {
return l
- } else if len(l) == 0 {
- return r
}
- v := make([]interface{}, 0, len(l)+len(r))
- return append(append(v, l...), r...)
+ v := make([]any, len(l)+len(r))
+ copy(v, l)
+ copy(v[len(l):], r)
+ return v
},
- func(l, r map[string]interface{}) interface{} {
- m := make(map[string]interface{}, len(l)+len(r))
+ func(l, r map[string]any) any {
+ if len(l) == 0 {
+ return r
+ }
+ if len(r) == 0 {
+ return l
+ }
+ m := make(map[string]any, len(l)+len(r))
for k, v := range l {
m[k] = v
}
@@ -336,63 +342,71 @@ func funcOpAdd(_, l, r interface{}) interface{} {
}
return m
},
- func(l, r interface{}) interface{} { return &binopTypeError{"add", l, r} },
+ func(l, r any) any {
+ if l == nil {
+ return r
+ }
+ if r == nil {
+ return l
+ }
+ return &binopTypeError{"add", l, r}
+ },
)
}
-func funcOpSub(_, l, r interface{}) interface{} {
+func funcOpSub(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} { return l - r },
- func(l, r float64) interface{} { return l - r },
- func(l, r *big.Int) interface{} { return new(big.Int).Sub(l, r) },
- func(l, r string) interface{} { return &binopTypeError{"subtract", l, r} },
- func(l, r []interface{}) interface{} {
- a := make([]interface{}, 0, len(l))
- for _, v := range l {
- var found bool
- for _, w := range r {
- if compare(v, w) == 0 {
- found = true
- break
+ func(l, r int) any {
+ if v := l - r; (v <= l) == (r >= 0) {
+ return v
+ }
+ x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+ return x.Sub(x, y)
+ },
+ func(l, r float64) any { return l - r },
+ func(l, r *big.Int) any { return new(big.Int).Sub(l, r) },
+ func(l, r string) any { return &binopTypeError{"subtract", l, r} },
+ func(l, r []any) any {
+ v := make([]any, 0, len(l))
+ L:
+ for _, l := range l {
+ for _, r := range r {
+ if compare(l, r) == 0 {
+ continue L
}
}
- if !found {
- a = append(a, v)
- }
+ v = append(v, l)
}
- return a
+ return v
},
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"subtract", l, r} },
+ func(l, r any) any { return &binopTypeError{"subtract", l, r} },
)
}
-func funcOpMul(_, l, r interface{}) interface{} {
+func funcOpMul(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} { return l * r },
- func(l, r float64) interface{} { return l * r },
- func(l, r *big.Int) interface{} { return new(big.Int).Mul(l, r) },
- func(l, r string) interface{} { return &binopTypeError{"multiply", l, r} },
- func(l, r []interface{}) interface{} { return &binopTypeError{"multiply", l, r} },
- deepMergeObjects,
- func(l, r interface{}) interface{} {
- multiplyString := func(s string, cnt float64) interface{} {
- if cnt <= 0.0 || cnt > float64(maxHalfInt/(16*(len(s)+1))) || math.IsNaN(cnt) {
- return nil
- }
- if cnt < 1.0 {
- return s
- }
- return strings.Repeat(s, int(cnt))
+ func(l, r int) any {
+ if v := l * r; r == 0 || v/r == l {
+ return v
}
+ x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+ return x.Mul(x, y)
+ },
+ func(l, r float64) any { return l * r },
+ func(l, r *big.Int) any { return new(big.Int).Mul(l, r) },
+ func(l, r string) any { return &binopTypeError{"multiply", l, r} },
+ func(l, r []any) any { return &binopTypeError{"multiply", l, r} },
+ deepMergeObjects,
+ func(l, r any) any {
if l, ok := l.(string); ok {
- if f, ok := toFloat(r); ok {
- return multiplyString(l, f)
+ if r, ok := toFloat(r); ok {
+ return repeatString(l, r)
}
}
if r, ok := r.(string); ok {
- if f, ok := toFloat(l); ok {
- return multiplyString(r, f)
+ if l, ok := toFloat(l); ok {
+ return repeatString(r, l)
}
}
return &binopTypeError{"multiply", l, r}
@@ -400,15 +414,15 @@ func funcOpMul(_, l, r interface{}) interface{} {
)
}
-func deepMergeObjects(l, r map[string]interface{}) interface{} {
- m := make(map[string]interface{}, len(l)+len(r))
+func deepMergeObjects(l, r map[string]any) any {
+ m := make(map[string]any, len(l)+len(r))
for k, v := range l {
m[k] = v
}
for k, v := range r {
if mk, ok := m[k]; ok {
- if mk, ok := mk.(map[string]interface{}); ok {
- if w, ok := v.(map[string]interface{}); ok {
+ if mk, ok := mk.(map[string]any); ok {
+ if w, ok := v.(map[string]any); ok {
v = deepMergeObjects(mk, w)
}
}
@@ -418,9 +432,19 @@ func deepMergeObjects(l, r map[string]interface{}) interface{} {
return m
}
-func funcOpDiv(_, l, r interface{}) interface{} {
+func repeatString(s string, n float64) any {
+ if n <= 0.0 || len(s) > 0 && n > float64(0x10000000/len(s)) || math.IsNaN(n) {
+ return nil
+ }
+ if int(n) < 1 {
+ return s
+ }
+ return strings.Repeat(s, int(n))
+}
+
+func funcOpDiv(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if r == 0 {
if l == 0 {
return math.NaN()
@@ -432,7 +456,7 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return float64(l) / float64(r)
},
- func(l, r float64) interface{} {
+ func(l, r float64) any {
if r == 0.0 {
if l == 0.0 {
return math.NaN()
@@ -441,7 +465,7 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return l / r
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
if r.Sign() == 0 {
if l.Sign() == 0 {
return math.NaN()
@@ -454,78 +478,78 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return bigToFloat(l) / bigToFloat(r)
},
- func(l, r string) interface{} {
+ func(l, r string) any {
if l == "" {
- return []interface{}{}
+ return []any{}
}
xs := strings.Split(l, r)
- vs := make([]interface{}, len(xs))
+ vs := make([]any, len(xs))
for i, x := range xs {
vs[i] = x
}
return vs
},
- func(l, r []interface{}) interface{} { return &binopTypeError{"divide", l, r} },
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"divide", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"divide", l, r} },
+ func(l, r []any) any { return &binopTypeError{"divide", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"divide", l, r} },
+ func(l, r any) any { return &binopTypeError{"divide", l, r} },
)
}
-func funcOpMod(_, l, r interface{}) interface{} {
+func funcOpMod(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if r == 0 {
return &zeroModuloError{l, r}
}
return l % r
},
- func(l, r float64) interface{} {
+ func(l, r float64) any {
ri := floatToInt(r)
if ri == 0 {
return &zeroModuloError{l, r}
}
return floatToInt(l) % ri
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
if r.Sign() == 0 {
return &zeroModuloError{l, r}
}
return new(big.Int).Rem(l, r)
},
- func(l, r string) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r []interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
+ func(l, r string) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r []any) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r any) any { return &binopTypeError{"modulo", l, r} },
)
}
-func funcOpAlt(_, l, r interface{}) interface{} {
+func funcOpAlt(_, l, r any) any {
if l == nil || l == false {
return r
}
return l
}
-func funcOpEq(_, l, r interface{}) interface{} {
+func funcOpEq(_, l, r any) any {
return compare(l, r) == 0
}
-func funcOpNe(_, l, r interface{}) interface{} {
+func funcOpNe(_, l, r any) any {
return compare(l, r) != 0
}
-func funcOpGt(_, l, r interface{}) interface{} {
+func funcOpGt(_, l, r any) any {
return compare(l, r) > 0
}
-func funcOpLt(_, l, r interface{}) interface{} {
+func funcOpLt(_, l, r any) any {
return compare(l, r) < 0
}
-func funcOpGe(_, l, r interface{}) interface{} {
+func funcOpGe(_, l, r any) any {
return compare(l, r) >= 0
}
-func funcOpLe(_, l, r interface{}) interface{} {
+func funcOpLe(_, l, r any) any {
return compare(l, r) <= 0
}
diff --git a/vendor/github.com/itchyny/gojq/option.go b/vendor/github.com/itchyny/gojq/option.go
index 5eb771cc..f1a110fa 100644
--- a/vendor/github.com/itchyny/gojq/option.go
+++ b/vendor/github.com/itchyny/gojq/option.go
@@ -6,7 +6,7 @@ import "fmt"
type CompilerOption func(*compiler)
// WithModuleLoader is a compiler option for module loader.
-// If you want to load modules from the filesystem, use NewModuleLoader.
+// If you want to load modules from the filesystem, use [NewModuleLoader].
func WithModuleLoader(moduleLoader ModuleLoader) CompilerOption {
return func(c *compiler) {
c.moduleLoader = moduleLoader
@@ -15,7 +15,7 @@ func WithModuleLoader(moduleLoader ModuleLoader) CompilerOption {
// WithEnvironLoader is a compiler option for environment variables loader.
// The OS environment variables are not accessible by default due to security
-// reason. You can pass os.Environ if you allow to access it.
+// reasons. You can specify [os.Environ] as argument if you allow to access.
func WithEnvironLoader(environLoader func() []string) CompilerOption {
return func(c *compiler) {
c.environLoader = environLoader
@@ -23,7 +23,7 @@ func WithEnvironLoader(environLoader func() []string) CompilerOption {
}
// WithVariables is a compiler option for variable names. The variables can be
-// used in the query. You have to give the values to code.Run in the same order.
+// used in the query. You have to give the values to [*Code.Run] in the same order.
func WithVariables(variables []string) CompilerOption {
return func(c *compiler) {
c.variables = variables
@@ -35,31 +35,28 @@ func WithVariables(variables []string) CompilerOption {
// values should satisfy 0 <= minarity <= maxarity <= 30, otherwise panics.
// On handling numbers, you should take account to int, float64 and *big.Int.
// These are the number types you are allowed to return, so do not return int64.
-// Refer to ValueError to return a value error just like built-in error function.
-// If you want to emit multiple values, call the empty function, accept a filter
-// for its argument, or call another built-in function, then use LoadInitModules
-// of the module loader.
-func WithFunction(name string, minarity, maxarity int,
- f func(interface{}, []interface{}) interface{}) CompilerOption {
+// Refer to [ValueError] to return a value error just like built-in error
+// function. If you want to emit multiple values, call the empty function,
+// accept a filter for its argument, or call another built-in function, then
+// use LoadInitModules of the module loader.
+func WithFunction(name string, minarity, maxarity int, f func(any, []any) any) CompilerOption {
return withFunction(name, minarity, maxarity, false, f)
}
// WithIterFunction is a compiler option for adding a custom iterator function.
-// This is like the WithFunction option, but you can add a function which
+// This is like the [WithFunction] option, but you can add a function which
// returns an Iter to emit multiple values. You cannot define both iterator and
// non-iterator functions of the same name (with possibly different arities).
-// See also NewIter, which can be used to convert values or an error to an Iter.
-func WithIterFunction(name string, minarity, maxarity int,
- f func(interface{}, []interface{}) Iter) CompilerOption {
+// See also [NewIter], which can be used to convert values or an error to an Iter.
+func WithIterFunction(name string, minarity, maxarity int, f func(any, []any) Iter) CompilerOption {
return withFunction(name, minarity, maxarity, true,
- func(v interface{}, args []interface{}) interface{} {
+ func(v any, args []any) any {
return f(v, args)
},
)
}
-func withFunction(name string, minarity, maxarity int, iter bool,
- f func(interface{}, []interface{}) interface{}) CompilerOption {
+func withFunction(name string, minarity, maxarity int, iter bool, f func(any, []any) any) CompilerOption {
if !(0 <= minarity && minarity <= maxarity && maxarity <= 30) {
panic(fmt.Sprintf("invalid arity for %q: %d, %d", name, minarity, maxarity))
}
@@ -74,7 +71,7 @@ func withFunction(name string, minarity, maxarity int, iter bool,
}
c.customFuncs[name] = function{
argcount | fn.argcount, iter,
- func(x interface{}, xs []interface{}) interface{} {
+ func(x any, xs []any) any {
if argcount&(1< 0 {
@@ -30,10 +35,10 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
return xs
}
-//line parser.go.y:28
+//line parser.go.y:33
type yySymType struct {
yys int
- value interface{}
+ value any
token string
operator Operator
}
@@ -61,24 +66,26 @@ const tokModuleVariable = 57365
const tokIndex = 57366
const tokNumber = 57367
const tokFormat = 57368
-const tokInvalid = 57369
-const tokString = 57370
-const tokStringStart = 57371
-const tokStringQuery = 57372
-const tokStringEnd = 57373
-const tokIf = 57374
-const tokThen = 57375
-const tokElif = 57376
-const tokElse = 57377
-const tokEnd = 57378
-const tokTry = 57379
-const tokCatch = 57380
-const tokReduce = 57381
-const tokForeach = 57382
-const tokRecurse = 57383
-const tokFuncDefPost = 57384
-const tokTermPost = 57385
-const tokEmptyCatch = 57386
+const tokString = 57369
+const tokStringStart = 57370
+const tokStringQuery = 57371
+const tokStringEnd = 57372
+const tokIf = 57373
+const tokThen = 57374
+const tokElif = 57375
+const tokElse = 57376
+const tokEnd = 57377
+const tokTry = 57378
+const tokCatch = 57379
+const tokReduce = 57380
+const tokForeach = 57381
+const tokRecurse = 57382
+const tokFuncDefPost = 57383
+const tokTermPost = 57384
+const tokEmptyCatch = 57385
+const tokInvalid = 57386
+const tokInvalidEscapeSequence = 57387
+const tokUnterminatedString = 57388
var yyToknames = [...]string{
"$end",
@@ -107,7 +114,6 @@ var yyToknames = [...]string{
"tokIndex",
"tokNumber",
"tokFormat",
- "tokInvalid",
"tokString",
"tokStringStart",
"tokStringQuery",
@@ -125,6 +131,9 @@ var yyToknames = [...]string{
"tokFuncDefPost",
"tokTermPost",
"tokEmptyCatch",
+ "tokInvalid",
+ "tokInvalidEscapeSequence",
+ "tokUnterminatedString",
"'|'",
"','",
"'+'",
@@ -150,15 +159,15 @@ const yyEofCode = 1
const yyErrCode = 2
const yyInitialStackSize = 16
-//line parser.go.y:687
+//line parser.go.y:693
//line yacctab:1
-var yyExca = [...]int{
+var yyExca = [...]int16{
-1, 1,
1, -1,
-2, 0,
-1, 97,
- 53, 0,
+ 55, 0,
-2, 104,
-1, 130,
5, 0,
@@ -167,167 +176,170 @@ var yyExca = [...]int{
9, 0,
-2, 35,
-1, 194,
- 56, 114,
+ 58, 114,
-2, 54,
}
const yyPrivate = 57344
-const yyLast = 1094
+const yyLast = 1127
-var yyAct = [...]int{
+var yyAct = [...]int16{
86, 214, 174, 112, 12, 203, 9, 175, 111, 31,
190, 6, 156, 140, 117, 47, 95, 97, 93, 94,
- 89, 227, 49, 75, 76, 7, 77, 78, 79, 240,
- 235, 103, 239, 106, 164, 123, 226, 119, 107, 108,
- 105, 234, 102, 75, 76, 113, 77, 78, 79, 163,
- 122, 104, 211, 75, 76, 210, 77, 78, 79, 158,
- 159, 264, 259, 243, 72, 74, 80, 81, 82, 83,
- 84, 229, 73, 127, 275, 128, 129, 130, 131, 132,
- 133, 134, 135, 136, 137, 138, 80, 81, 82, 83,
- 84, 228, 73, 147, 72, 74, 80, 81, 82, 83,
- 84, 145, 73, 141, 278, 161, 246, 277, 157, 225,
- 166, 165, 144, 126, 125, 167, 88, 42, 43, 245,
- 124, 258, 224, 206, 179, 180, 181, 44, 183, 184,
- 73, 242, 177, 154, 153, 178, 142, 186, 49, 173,
- 267, 100, 143, 92, 91, 90, 92, 191, 99, 197,
- 150, 120, 200, 192, 201, 202, 188, 256, 257, 207,
- 88, 182, 98, 198, 199, 209, 219, 7, 216, 101,
- 215, 215, 218, 213, 113, 155, 185, 75, 76, 3,
- 77, 78, 79, 42, 43, 221, 222, 28, 91, 90,
- 92, 179, 180, 181, 230, 204, 205, 232, 8, 177,
- 223, 27, 178, 80, 81, 82, 83, 84, 220, 73,
- 85, 157, 241, 176, 46, 149, 237, 110, 72, 74,
- 80, 81, 82, 83, 84, 88, 73, 152, 182, 196,
- 79, 191, 195, 255, 7, 253, 254, 192, 248, 247,
- 236, 160, 249, 250, 96, 262, 260, 261, 215, 263,
- 11, 121, 189, 91, 90, 92, 11, 268, 269, 187,
- 270, 82, 83, 84, 139, 73, 272, 273, 80, 81,
- 82, 83, 84, 208, 73, 279, 10, 5, 271, 280,
- 51, 52, 4, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 115, 116, 170, 2, 171, 169, 1,
- 0, 42, 43, 0, 0, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, 0, 0, 20, 0, 17, 37,
- 24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
- 114, 42, 43, 0, 212, 15, 0, 0, 0, 0,
- 16, 0, 13, 14, 22, 0, 0, 0, 0, 0,
- 33, 34, 0, 0, 0, 21, 0, 36, 0, 148,
- 32, 0, 146, 35, 51, 52, 0, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 115, 116, 0,
+ 89, 141, 49, 7, 179, 180, 181, 240, 246, 264,
+ 239, 103, 177, 106, 178, 227, 164, 119, 107, 108,
+ 105, 245, 102, 75, 76, 113, 77, 78, 79, 123,
+ 226, 163, 211, 225, 259, 210, 142, 179, 180, 181,
+ 158, 159, 143, 182, 122, 177, 224, 178, 219, 7,
+ 235, 234, 104, 127, 243, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 72, 74, 80, 81,
+ 82, 83, 84, 147, 73, 88, 182, 196, 73, 229,
+ 195, 145, 7, 150, 228, 161, 166, 165, 157, 126,
+ 125, 124, 144, 88, 258, 167, 80, 81, 82, 83,
+ 84, 206, 73, 44, 242, 91, 90, 92, 183, 184,
+ 82, 83, 84, 154, 73, 153, 267, 186, 49, 173,
+ 42, 43, 100, 91, 90, 92, 99, 191, 120, 197,
+ 256, 257, 200, 192, 201, 202, 188, 75, 76, 207,
+ 77, 78, 79, 198, 199, 209, 42, 43, 216, 92,
+ 215, 215, 218, 213, 113, 98, 75, 76, 185, 77,
+ 78, 79, 204, 205, 101, 221, 222, 170, 155, 171,
+ 169, 3, 28, 27, 230, 96, 220, 232, 176, 46,
+ 223, 11, 80, 81, 82, 83, 84, 11, 73, 78,
+ 79, 157, 241, 110, 8, 152, 237, 255, 236, 72,
+ 74, 80, 81, 82, 83, 84, 85, 73, 79, 278,
+ 160, 191, 277, 121, 189, 253, 254, 192, 248, 247,
+ 187, 139, 249, 250, 208, 262, 260, 261, 215, 263,
+ 80, 81, 82, 83, 84, 149, 73, 268, 269, 10,
+ 270, 5, 4, 2, 1, 88, 272, 273, 80, 81,
+ 82, 83, 84, 0, 73, 279, 0, 0, 271, 280,
+ 51, 52, 0, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 115, 116, 91, 90, 92, 0, 0,
+ 42, 43, 0, 87, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, 88, 0, 20, 0, 17, 37, 24,
+ 25, 26, 38, 40, 39, 41, 23, 29, 30, 42,
+ 43, 0, 114, 15, 0, 0, 212, 0, 16, 0,
+ 13, 14, 22, 91, 90, 92, 0, 0, 0, 0,
+ 0, 33, 34, 0, 0, 0, 21, 0, 36, 0,
+ 148, 32, 0, 146, 35, 51, 52, 0, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 115, 116,
0, 0, 0, 0, 0, 42, 43, 0, 0, 63,
64, 65, 66, 67, 68, 69, 70, 71, 18, 19,
20, 0, 17, 37, 24, 25, 26, 38, 40, 39,
- 41, 23, 29, 30, 114, 42, 43, 0, 109, 15,
- 0, 0, 0, 0, 16, 0, 13, 14, 22, 0,
+ 41, 23, 29, 30, 42, 43, 0, 114, 15, 0,
+ 0, 109, 0, 16, 0, 13, 14, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 34, 0, 0,
+ 0, 21, 0, 36, 0, 0, 32, 0, 20, 35,
+ 17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+ 29, 30, 42, 43, 0, 0, 15, 0, 0, 0,
+ 0, 16, 0, 13, 14, 22, 0, 0, 0, 0,
0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
- 0, 36, 0, 0, 32, 0, 20, 35, 17, 37,
- 24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
- 0, 42, 43, 0, 0, 15, 0, 0, 0, 0,
- 16, 0, 13, 14, 22, 0, 87, 0, 0, 0,
- 33, 34, 0, 0, 0, 21, 88, 36, 0, 0,
- 32, 0, 231, 35, 20, 0, 17, 37, 24, 25,
- 26, 38, 40, 39, 41, 23, 29, 30, 0, 42,
- 43, 0, 0, 15, 91, 90, 92, 0, 16, 0,
- 13, 14, 22, 0, 0, 0, 0, 0, 33, 34,
- 0, 0, 0, 21, 0, 36, 0, 0, 32, 0,
- 118, 35, 20, 0, 17, 37, 24, 25, 26, 38,
- 40, 39, 41, 23, 29, 30, 0, 42, 43, 0,
- 0, 15, 0, 77, 78, 79, 16, 0, 13, 14,
- 22, 0, 0, 0, 0, 0, 33, 34, 0, 0,
- 0, 21, 0, 36, 0, 0, 32, 51, 52, 35,
- 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
- 48, 0, 0, 80, 81, 82, 83, 84, 50, 73,
- 0, 0, 63, 64, 65, 66, 67, 68, 69, 70,
+ 0, 36, 0, 0, 32, 0, 231, 35, 20, 0,
+ 17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+ 29, 30, 42, 43, 0, 0, 15, 0, 0, 0,
+ 0, 16, 0, 13, 14, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
+ 0, 36, 0, 0, 32, 0, 118, 35, 20, 0,
+ 17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+ 29, 30, 42, 43, 0, 0, 15, 0, 77, 78,
+ 79, 16, 0, 13, 14, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
+ 0, 36, 0, 0, 32, 51, 52, 35, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 48, 0,
+ 80, 81, 82, 83, 84, 50, 73, 0, 0, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 51, 52,
+ 0, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 48, 0, 0, 0, 0, 0, 0, 50, 0,
+ 0, 172, 63, 64, 65, 66, 67, 68, 69, 70,
71, 51, 52, 0, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 48, 0, 0, 0, 0, 0,
- 0, 172, 50, 0, 0, 0, 63, 64, 65, 66,
- 67, 68, 69, 70, 71, 51, 52, 0, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 115, 194,
- 78, 79, 0, 0, 0, 45, 42, 43, 0, 0,
- 63, 64, 65, 66, 67, 68, 69, 70, 71, 37,
- 24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
- 0, 42, 43, 75, 76, 193, 77, 78, 79, 80,
- 81, 82, 83, 84, 22, 73, 0, 0, 0, 0,
- 33, 34, 0, 0, 0, 21, 0, 36, 0, 0,
- 32, 75, 76, 35, 77, 78, 79, 0, 0, 0,
- 0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
- 84, 0, 73, 0, 0, 0, 75, 76, 252, 77,
- 78, 79, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
- 73, 0, 0, 0, 75, 76, 233, 77, 78, 79,
- 0, 0, 0, 0, 0, 0, 0, 72, 74, 80,
- 81, 82, 83, 84, 0, 73, 0, 0, 0, 75,
- 76, 168, 77, 78, 79, 0, 0, 0, 0, 0,
+ 59, 60, 61, 62, 115, 194, 0, 0, 0, 0,
+ 0, 42, 43, 0, 45, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 37, 24, 25, 26, 38, 40,
+ 39, 41, 23, 29, 30, 42, 43, 75, 76, 0,
+ 77, 78, 79, 193, 0, 0, 0, 0, 22, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 34, 0,
+ 0, 0, 21, 0, 36, 0, 0, 32, 75, 76,
+ 35, 77, 78, 79, 0, 0, 0, 0, 0, 0,
+ 72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
+ 0, 0, 75, 76, 252, 77, 78, 79, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 72, 74, 80, 81, 82, 83, 84, 0, 73,
+ 0, 0, 0, 75, 76, 233, 77, 78, 79, 0,
0, 0, 0, 0, 0, 72, 74, 80, 81, 82,
- 83, 84, 0, 73, 0, 0, 75, 76, 281, 77,
- 78, 79, 0, 0, 0, 0, 0, 0, 0, 0,
+ 83, 84, 0, 73, 0, 0, 0, 75, 76, 168,
+ 77, 78, 79, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 72, 74, 80, 81,
+ 82, 83, 84, 0, 73, 0, 0, 75, 76, 281,
+ 77, 78, 79, 0, 0, 0, 0, 0, 0, 0,
72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
0, 75, 76, 276, 77, 78, 79, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 72, 74, 80,
- 81, 82, 83, 84, 0, 73, 0, 0, 75, 76,
- 251, 77, 78, 79, 0, 0, 0, 0, 0, 0,
- 0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
- 73, 0, 0, 75, 76, 244, 77, 78, 79, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
- 74, 80, 81, 82, 83, 84, 0, 73, 0, 0,
- 75, 76, 217, 77, 78, 79, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
+ 0, 75, 76, 251, 77, 78, 79, 0, 0, 0,
0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
- 84, 0, 73, 0, 0, 75, 76, 162, 77, 78,
+ 84, 0, 73, 0, 0, 75, 76, 244, 77, 78,
79, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 72, 74, 80, 81, 82, 83, 84, 0, 73,
- 0, 266, 75, 76, 0, 77, 78, 79, 0, 0,
- 0, 0, 0, 0, 0, 0, 72, 74, 80, 81,
- 82, 83, 84, 0, 73, 0, 265, 75, 76, 0,
- 77, 78, 79, 0, 0, 0, 75, 76, 0, 77,
- 78, 79, 0, 72, 74, 80, 81, 82, 83, 84,
- 0, 73, 0, 238, 75, 76, 274, 77, 78, 79,
- 0, 0, 0, 0, 0, 151, 0, 0, 72, 74,
- 80, 81, 82, 83, 84, 0, 73, 72, 74, 80,
- 81, 82, 83, 84, 0, 73, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 72, 74, 80, 81, 82,
- 83, 84, 0, 73,
+ 0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
+ 84, 0, 73, 0, 0, 75, 76, 217, 77, 78,
+ 79, 0, 0, 0, 0, 0, 0, 0, 72, 74,
+ 80, 81, 82, 83, 84, 0, 73, 0, 0, 75,
+ 76, 162, 77, 78, 79, 0, 0, 0, 0, 0,
+ 75, 76, 0, 77, 78, 79, 0, 0, 72, 74,
+ 80, 81, 82, 83, 84, 0, 73, 0, 275, 75,
+ 76, 0, 77, 78, 79, 0, 0, 0, 0, 0,
+ 0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
+ 73, 0, 266, 72, 74, 80, 81, 82, 83, 84,
+ 0, 73, 0, 265, 75, 76, 0, 77, 78, 79,
+ 0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
+ 73, 0, 238, 0, 0, 0, 75, 76, 0, 77,
+ 78, 79, 274, 0, 0, 75, 76, 0, 77, 78,
+ 79, 0, 0, 0, 0, 0, 0, 72, 74, 80,
+ 81, 82, 83, 84, 151, 73, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+ 74, 80, 81, 82, 83, 84, 0, 73, 72, 74,
+ 80, 81, 82, 83, 84, 0, 73,
}
-var yyPact = [...]int{
- 169, -1000, -1000, -35, -1000, 387, 72, 614, -1000, 1040,
- -1000, 529, 462, 673, 673, 529, 529, 141, 120, 113,
- 149, 89, -1000, -1000, -1000, -1000, -1000, -6, -1000, -1000,
- 155, -1000, 529, 673, 673, 357, 481, 130, -1000, -1000,
- -1000, -1000, -1000, -1000, -1000, -1000, -11, -1000, 64, 58,
- 57, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+var yyPact = [...]int16{
+ 181, -1000, -1000, -39, -1000, 387, 66, 621, -1000, 1071,
+ -1000, 535, 289, 678, 678, 535, 535, 154, 119, 115,
+ 164, 113, -1000, -1000, -1000, -1000, -1000, 13, -1000, -1000,
+ 139, -1000, 535, 678, 678, 358, 485, 127, -1000, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, 1, -1000, 53, 52,
+ 51, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
- -1000, -1000, 529, -1000, 529, 529, 529, 529, 529, 529,
- 529, 529, 529, 529, 529, -1000, 1040, 82, -1000, -1000,
- -1000, 89, 303, 201, 136, 1022, 529, 96, 88, 161,
- -35, 3, -1000, -1000, 529, -1000, 909, 92, 92, -1000,
- -12, -1000, 55, 54, 529, -1000, -1000, -1000, -1000, 752,
- -1000, 267, -1000, 580, 174, 174, 174, 1040, 39, 39,
- 556, 662, 221, 156, 212, 212, 77, 77, 77, 131,
- -1000, -1000, 82, 648, -1000, -1000, -1000, 173, 529, 82,
- 82, 529, -1000, 529, 529, 175, 68, -1000, 529, 175,
- -3, 1040, -1000, -1000, 273, 673, 673, 884, -1000, -1000,
- -1000, 529, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
- -1000, -1000, 107, -1000, -1000, 529, 82, 63, -1000, -25,
- -1000, 35, 15, 529, -1000, -1000, 433, 727, -16, -27,
- 1040, -1000, 1040, -35, -1000, -1000, -1000, 988, -26, -1000,
- -1000, 529, -1000, -1000, 86, 92, 86, 7, 857, -1000,
- 60, -1000, 1040, -1000, -1000, 82, -1000, 648, 82, 82,
- 832, -1000, 699, -1000, 529, 529, 123, 66, -1000, 6,
- 175, 1040, 673, 673, -1000, -1000, 174, -1000, -1000, -1000,
- -1000, 5, -1000, 961, 936, 104, 529, 529, -1000, 529,
- -1000, 92, 86, -1000, 82, 529, 529, -1000, 1013, 1040,
- 19, -1000, 805, 49, 529, -1000, -1000, -1000, 529, 1040,
- 780, -1000,
+ -1000, -1000, 535, -1000, 535, 535, 535, 535, 535, 535,
+ 535, 535, 535, 535, 535, -1000, 1071, 0, -1000, -1000,
+ -1000, 113, 302, 241, 89, 1062, 535, 98, 86, 174,
+ -39, 2, -1000, -1000, 535, -1000, 921, 71, 71, -1000,
+ -12, -1000, 49, 48, 535, -1000, -1000, -1000, -1000, 758,
+ -1000, 160, -1000, 588, 40, 40, 40, 1071, 153, 153,
+ 561, 201, 219, 67, 79, 79, 43, 43, 43, 131,
+ -1000, -1000, 0, 654, -1000, -1000, -1000, 39, 535, 0,
+ 0, 535, -1000, 535, 535, 162, 64, -1000, 535, 162,
+ -5, 1071, -1000, -1000, 273, 678, 678, 897, -1000, -1000,
+ -1000, 535, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, 7, -1000, -1000, 535, 0, 5, -1000, -13,
+ -1000, 46, 41, 535, -1000, -1000, 435, 734, 12, 11,
+ 1071, -1000, 1071, -39, -1000, -1000, -1000, 1005, -30, -1000,
+ -1000, 535, -1000, -1000, 77, 71, 77, 16, 867, -1000,
+ -20, -1000, 1071, -1000, -1000, 0, -1000, 654, 0, 0,
+ 843, -1000, 703, -1000, 535, 535, 117, 57, -1000, -4,
+ 162, 1071, 678, 678, -1000, -1000, 40, -1000, -1000, -1000,
+ -1000, -29, -1000, 986, 975, 101, 535, 535, -1000, 535,
+ -1000, 71, 77, -1000, 0, 535, 535, -1000, 1040, 1071,
+ 951, -1000, 813, 172, 535, -1000, -1000, -1000, 535, 1071,
+ 789, -1000,
}
-var yyPgo = [...]int{
- 0, 299, 296, 282, 277, 276, 12, 198, 244, 273,
- 0, 264, 13, 259, 252, 10, 4, 9, 251, 20,
- 241, 240, 233, 227, 217, 8, 1, 2, 7, 214,
- 15, 213, 208, 5, 201, 187, 14, 3,
+var yyPgo = [...]int16{
+ 0, 264, 263, 262, 261, 259, 12, 214, 195, 244,
+ 0, 241, 13, 240, 234, 10, 4, 9, 233, 20,
+ 230, 218, 217, 215, 213, 8, 1, 2, 7, 199,
+ 15, 198, 196, 5, 193, 192, 14, 3,
}
-var yyR1 = [...]int{
+var yyR1 = [...]int8{
0, 1, 2, 2, 3, 3, 4, 4, 5, 5,
6, 6, 7, 7, 8, 8, 9, 9, 33, 33,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
@@ -346,7 +358,7 @@ var yyR1 = [...]int{
36, 36, 36, 36, 36, 36, 36, 36,
}
-var yyR2 = [...]int{
+var yyR2 = [...]int8{
0, 2, 0, 3, 2, 2, 0, 2, 6, 4,
0, 1, 0, 2, 5, 8, 1, 3, 1, 1,
2, 3, 5, 9, 9, 11, 7, 3, 4, 2,
@@ -365,39 +377,39 @@ var yyR2 = [...]int{
1, 1, 1, 1, 1, 1, 1, 1,
}
-var yyChk = [...]int{
- -1000, -1, -2, 10, -3, -4, -28, 60, -7, -10,
- -5, -8, -16, 39, 40, 32, 37, 15, 11, 12,
- 13, 52, 41, 24, 17, 18, 19, -34, -35, 25,
- 26, -17, 57, 47, 48, 60, 54, 16, 20, 22,
- 21, 23, 28, 29, 55, 61, -29, -30, 20, -36,
- 28, 7, 8, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 45, 53, 46, 4, 5, 7, 8, 9,
- 47, 48, 49, 50, 51, -7, -10, 14, 24, -19,
- 53, 52, 54, -16, -16, -10, -8, -10, 21, 28,
- 28, 20, -19, -17, 57, -17, -10, -16, -16, 61,
- -24, -25, -37, -17, 57, 20, 21, -36, 59, -10,
- 21, -18, 61, 46, 56, 56, 56, -10, -10, -10,
+var yyChk = [...]int16{
+ -1000, -1, -2, 10, -3, -4, -28, 62, -7, -10,
+ -5, -8, -16, 38, 39, 31, 36, 15, 11, 12,
+ 13, 54, 40, 24, 17, 18, 19, -34, -35, 25,
+ 26, -17, 59, 49, 50, 62, 56, 16, 20, 22,
+ 21, 23, 27, 28, 57, 63, -29, -30, 20, -36,
+ 27, 7, 8, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 47, 55, 48, 4, 5, 7, 8, 9,
+ 49, 50, 51, 52, 53, -7, -10, 14, 24, -19,
+ 55, 54, 56, -16, -16, -10, -8, -10, 21, 27,
+ 27, 20, -19, -17, 59, -17, -10, -16, -16, 63,
+ -24, -25, -37, -17, 59, 20, 21, -36, 61, -10,
+ 21, -18, 63, 48, 58, 58, 58, -10, -10, -10,
-10, -10, -10, -10, -10, -10, -10, -10, -10, -11,
- -12, 21, 54, 60, -19, -17, 59, -10, 56, 14,
- 14, 33, -23, 38, 45, 14, -6, -28, 56, 57,
- -20, -10, 58, 61, 46, 56, 56, -10, 59, 31,
- 28, 30, 61, -30, -27, -28, -31, 25, 28, 17,
- 18, 19, 54, -27, -27, 45, 6, -13, -12, -14,
- -15, -37, -17, 57, 21, 59, 56, -10, -12, -12,
- -10, -10, -10, -33, 20, 21, 55, -10, -9, -33,
- 58, 55, 61, -25, -26, -16, -26, 58, -10, 59,
- -32, -27, -10, -12, 59, 46, 61, 46, 56, 56,
- -10, 59, -10, 59, 57, 57, -21, -6, 55, 58,
- 55, -10, 45, 56, 58, 59, 46, -12, -15, -12,
- -12, 58, 59, -10, -10, -22, 34, 35, 55, 56,
- -33, -16, -26, -27, 56, 55, 55, 36, -10, -10,
- -10, -12, -10, -10, 33, 55, 58, 58, 55, -10,
- -10, 58,
+ -12, 21, 56, 62, -19, -17, 61, -10, 58, 14,
+ 14, 32, -23, 37, 47, 14, -6, -28, 58, 59,
+ -20, -10, 60, 63, 48, 58, 58, -10, 61, 30,
+ 27, 29, 63, -30, -27, -28, -31, 25, 27, 17,
+ 18, 19, 56, -27, -27, 47, 6, -13, -12, -14,
+ -15, -37, -17, 59, 21, 61, 58, -10, -12, -12,
+ -10, -10, -10, -33, 20, 21, 57, -10, -9, -33,
+ 60, 57, 63, -25, -26, -16, -26, 60, -10, 61,
+ -32, -27, -10, -12, 61, 48, 63, 48, 58, 58,
+ -10, 61, -10, 61, 59, 59, -21, -6, 57, 60,
+ 57, -10, 47, 58, 60, 61, 48, -12, -15, -12,
+ -12, 60, 61, -10, -10, -22, 33, 34, 57, 58,
+ -33, -16, -26, -27, 58, 57, 57, 35, -10, -10,
+ -10, -12, -10, -10, 32, 57, 60, 60, 57, -10,
+ -10, 60,
}
-var yyDef = [...]int{
+var yyDef = [...]int16{
2, -2, 6, 0, 1, 12, 0, 0, 4, 5,
7, 12, 41, 0, 0, 0, 0, 0, 0, 0,
0, 55, 56, 57, 60, 61, 62, 63, 65, 66,
@@ -429,31 +441,31 @@ var yyDef = [...]int{
0, 25,
}
-var yyTok1 = [...]int{
+var yyTok1 = [...]int8{
1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 51, 3, 3,
- 57, 58, 49, 47, 46, 48, 52, 50, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 56, 55,
- 3, 3, 3, 53, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 53, 3, 3,
+ 59, 60, 51, 49, 48, 50, 54, 52, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 58, 57,
+ 3, 3, 3, 55, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 54, 3, 59, 3, 3, 3, 3, 3, 3,
+ 3, 56, 3, 61, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 60, 45, 61,
+ 3, 3, 3, 62, 47, 63,
}
-var yyTok2 = [...]int{
+var yyTok2 = [...]int8{
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
- 42, 43, 44,
+ 42, 43, 44, 45, 46,
}
-var yyTok3 = [...]int{
+var yyTok3 = [...]int8{
0,
}
@@ -535,9 +547,9 @@ func yyErrorMessage(state, lookAhead int) string {
expected := make([]int, 0, 4)
// Look for shiftable tokens.
- base := yyPact[state]
+ base := int(yyPact[state])
for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
- if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
+ if n := base + tok; n >= 0 && n < yyLast && int(yyChk[int(yyAct[n])]) == tok {
if len(expected) == cap(expected) {
return res
}
@@ -547,13 +559,13 @@ func yyErrorMessage(state, lookAhead int) string {
if yyDef[state] == -2 {
i := 0
- for yyExca[i] != -1 || yyExca[i+1] != state {
+ for yyExca[i] != -1 || int(yyExca[i+1]) != state {
i += 2
}
// Look for tokens that we accept or reduce.
for i += 2; yyExca[i] >= 0; i += 2 {
- tok := yyExca[i]
+ tok := int(yyExca[i])
if tok < TOKSTART || yyExca[i+1] == 0 {
continue
}
@@ -584,30 +596,30 @@ func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
token = 0
char = lex.Lex(lval)
if char <= 0 {
- token = yyTok1[0]
+ token = int(yyTok1[0])
goto out
}
if char < len(yyTok1) {
- token = yyTok1[char]
+ token = int(yyTok1[char])
goto out
}
if char >= yyPrivate {
if char < yyPrivate+len(yyTok2) {
- token = yyTok2[char-yyPrivate]
+ token = int(yyTok2[char-yyPrivate])
goto out
}
}
for i := 0; i < len(yyTok3); i += 2 {
- token = yyTok3[i+0]
+ token = int(yyTok3[i+0])
if token == char {
- token = yyTok3[i+1]
+ token = int(yyTok3[i+1])
goto out
}
}
out:
if token == 0 {
- token = yyTok2[1] /* unknown char */
+ token = int(yyTok2[1]) /* unknown char */
}
if yyDebug >= 3 {
__yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char))
@@ -662,7 +674,7 @@ yystack:
yyS[yyp].yys = yystate
yynewstate:
- yyn = yyPact[yystate]
+ yyn = int(yyPact[yystate])
if yyn <= yyFlag {
goto yydefault /* simple state */
}
@@ -673,8 +685,8 @@ yynewstate:
if yyn < 0 || yyn >= yyLast {
goto yydefault
}
- yyn = yyAct[yyn]
- if yyChk[yyn] == yytoken { /* valid shift */
+ yyn = int(yyAct[yyn])
+ if int(yyChk[yyn]) == yytoken { /* valid shift */
yyrcvr.char = -1
yytoken = -1
yyVAL = yyrcvr.lval
@@ -687,7 +699,7 @@ yynewstate:
yydefault:
/* default state action */
- yyn = yyDef[yystate]
+ yyn = int(yyDef[yystate])
if yyn == -2 {
if yyrcvr.char < 0 {
yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
@@ -696,18 +708,18 @@ yydefault:
/* look through exception table */
xi := 0
for {
- if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate {
+ if yyExca[xi+0] == -1 && int(yyExca[xi+1]) == yystate {
break
}
xi += 2
}
for xi += 2; ; xi += 2 {
- yyn = yyExca[xi+0]
+ yyn = int(yyExca[xi+0])
if yyn < 0 || yyn == yytoken {
break
}
}
- yyn = yyExca[xi+1]
+ yyn = int(yyExca[xi+1])
if yyn < 0 {
goto ret0
}
@@ -729,10 +741,10 @@ yydefault:
/* find a state where "error" is a legal shift action */
for yyp >= 0 {
- yyn = yyPact[yyS[yyp].yys] + yyErrCode
+ yyn = int(yyPact[yyS[yyp].yys]) + yyErrCode
if yyn >= 0 && yyn < yyLast {
- yystate = yyAct[yyn] /* simulate a shift of "error" */
- if yyChk[yystate] == yyErrCode {
+ yystate = int(yyAct[yyn]) /* simulate a shift of "error" */
+ if int(yyChk[yystate]) == yyErrCode {
goto yystack
}
}
@@ -768,7 +780,7 @@ yydefault:
yypt := yyp
_ = yypt // guard against "declared and not used"
- yyp -= yyR2[yyn]
+ yyp -= int(yyR2[yyn])
// yyp is now the index of $0. Perform the default action. Iff the
// reduced production is ε, $1 is possibly out of range.
if yyp+1 >= len(yyS) {
@@ -779,16 +791,16 @@ yydefault:
yyVAL = yyS[yyp+1]
/* consult goto table to find next state */
- yyn = yyR1[yyn]
- yyg := yyPgo[yyn]
+ yyn = int(yyR1[yyn])
+ yyg := int(yyPgo[yyn])
yyj := yyg + yyS[yyp].yys + 1
if yyj >= yyLast {
- yystate = yyAct[yyg]
+ yystate = int(yyAct[yyg])
} else {
- yystate = yyAct[yyj]
- if yyChk[yystate] != -yyn {
- yystate = yyAct[yyg]
+ yystate = int(yyAct[yyj])
+ if int(yyChk[yystate]) != -yyn {
+ yystate = int(yyAct[yyg])
}
}
// dummy call; replaced with literal code
@@ -796,7 +808,7 @@ yydefault:
case 1:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:67
+//line parser.go.y:73
{
if yyDollar[1].value != nil {
yyDollar[2].value.(*Query).Meta = yyDollar[1].value.(*ConstObject)
@@ -805,25 +817,25 @@ yydefault:
}
case 2:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:74
+//line parser.go.y:80
{
yyVAL.value = nil
}
case 3:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:78
+//line parser.go.y:84
{
yyVAL.value = yyDollar[2].value
}
case 4:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:84
+//line parser.go.y:90
{
yyVAL.value = &Query{Imports: yyDollar[1].value.([]*Import), FuncDefs: reverseFuncDef(yyDollar[2].value.([]*FuncDef)), Term: &Term{Type: TermTypeIdentity}}
}
case 5:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:88
+//line parser.go.y:94
{
if yyDollar[1].value != nil {
yyDollar[2].value.(*Query).Imports = yyDollar[1].value.([]*Import)
@@ -832,144 +844,144 @@ yydefault:
}
case 6:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:95
+//line parser.go.y:101
{
yyVAL.value = []*Import(nil)
}
case 7:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:99
+//line parser.go.y:105
{
yyVAL.value = append(yyDollar[1].value.([]*Import), yyDollar[2].value.(*Import))
}
case 8:
yyDollar = yyS[yypt-6 : yypt+1]
-//line parser.go.y:105
+//line parser.go.y:111
{
yyVAL.value = &Import{ImportPath: yyDollar[2].token, ImportAlias: yyDollar[4].token, Meta: yyDollar[5].value.(*ConstObject)}
}
case 9:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:109
+//line parser.go.y:115
{
yyVAL.value = &Import{IncludePath: yyDollar[2].token, Meta: yyDollar[3].value.(*ConstObject)}
}
case 10:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:115
+//line parser.go.y:121
{
yyVAL.value = (*ConstObject)(nil)
}
case 11:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:118
+//line parser.go.y:124
{
}
case 12:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:122
+//line parser.go.y:128
{
yyVAL.value = []*FuncDef(nil)
}
case 13:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:126
+//line parser.go.y:132
{
yyVAL.value = append(yyDollar[2].value.([]*FuncDef), yyDollar[1].value.(*FuncDef))
}
case 14:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:132
+//line parser.go.y:138
{
yyVAL.value = &FuncDef{Name: yyDollar[2].token, Body: yyDollar[4].value.(*Query)}
}
case 15:
yyDollar = yyS[yypt-8 : yypt+1]
-//line parser.go.y:136
+//line parser.go.y:142
{
yyVAL.value = &FuncDef{yyDollar[2].token, yyDollar[4].value.([]string), yyDollar[7].value.(*Query)}
}
case 16:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:142
+//line parser.go.y:148
{
yyVAL.value = []string{yyDollar[1].token}
}
case 17:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:146
+//line parser.go.y:152
{
yyVAL.value = append(yyDollar[1].value.([]string), yyDollar[3].token)
}
case 18:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:151
+//line parser.go.y:157
{
}
case 19:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:152
+//line parser.go.y:158
{
}
case 20:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:156
+//line parser.go.y:162
{
yyDollar[2].value.(*Query).FuncDefs = prependFuncDef(yyDollar[2].value.(*Query).FuncDefs, yyDollar[1].value.(*FuncDef))
yyVAL.value = yyDollar[2].value
}
case 21:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:161
+//line parser.go.y:167
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpPipe, Right: yyDollar[3].value.(*Query)}
}
case 22:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:165
+//line parser.go.y:171
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Bind: &Bind{yyDollar[3].value.([]*Pattern), yyDollar[5].value.(*Query)}})
yyVAL.value = &Query{Term: yyDollar[1].value.(*Term)}
}
case 23:
yyDollar = yyS[yypt-9 : yypt+1]
-//line parser.go.y:170
+//line parser.go.y:176
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query)}}}
}
case 24:
yyDollar = yyS[yypt-9 : yypt+1]
-//line parser.go.y:174
+//line parser.go.y:180
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query), nil}}}
}
case 25:
yyDollar = yyS[yypt-11 : yypt+1]
-//line parser.go.y:178
+//line parser.go.y:184
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query), yyDollar[10].value.(*Query)}}}
}
case 26:
yyDollar = yyS[yypt-7 : yypt+1]
-//line parser.go.y:182
+//line parser.go.y:188
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeIf, If: &If{yyDollar[2].value.(*Query), yyDollar[4].value.(*Query), yyDollar[5].value.([]*IfElif), yyDollar[6].value.(*Query)}}}
}
case 27:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:186
+//line parser.go.y:192
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeTry, Try: &Try{yyDollar[2].value.(*Query), yyDollar[3].value.(*Query)}}}
}
case 28:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:190
+//line parser.go.y:196
{
yyVAL.value = &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{yyDollar[2].token, yyDollar[4].value.(*Query)}}}
}
case 29:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:194
+//line parser.go.y:200
{
if t := yyDollar[1].value.(*Query).Term; t != nil {
t.SuffixList = append(t.SuffixList, &Suffix{Optional: true})
@@ -979,175 +991,175 @@ yydefault:
}
case 30:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:202
+//line parser.go.y:208
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpComma, Right: yyDollar[3].value.(*Query)}
}
case 31:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:206
+//line parser.go.y:212
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
}
case 32:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:210
+//line parser.go.y:216
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
}
case 33:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:214
+//line parser.go.y:220
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpOr, Right: yyDollar[3].value.(*Query)}
}
case 34:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:218
+//line parser.go.y:224
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpAnd, Right: yyDollar[3].value.(*Query)}
}
case 35:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:222
+//line parser.go.y:228
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
}
case 36:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:226
+//line parser.go.y:232
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpAdd, Right: yyDollar[3].value.(*Query)}
}
case 37:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:230
+//line parser.go.y:236
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpSub, Right: yyDollar[3].value.(*Query)}
}
case 38:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:234
+//line parser.go.y:240
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpMul, Right: yyDollar[3].value.(*Query)}
}
case 39:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:238
+//line parser.go.y:244
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpDiv, Right: yyDollar[3].value.(*Query)}
}
case 40:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:242
+//line parser.go.y:248
{
yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpMod, Right: yyDollar[3].value.(*Query)}
}
case 41:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:246
+//line parser.go.y:252
{
yyVAL.value = &Query{Term: yyDollar[1].value.(*Term)}
}
case 42:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:252
+//line parser.go.y:258
{
yyVAL.value = []*Pattern{yyDollar[1].value.(*Pattern)}
}
case 43:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:256
+//line parser.go.y:262
{
yyVAL.value = append(yyDollar[1].value.([]*Pattern), yyDollar[3].value.(*Pattern))
}
case 44:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:262
+//line parser.go.y:268
{
yyVAL.value = &Pattern{Name: yyDollar[1].token}
}
case 45:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:266
+//line parser.go.y:272
{
yyVAL.value = &Pattern{Array: yyDollar[2].value.([]*Pattern)}
}
case 46:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:270
+//line parser.go.y:276
{
yyVAL.value = &Pattern{Object: yyDollar[2].value.([]*PatternObject)}
}
case 47:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:276
+//line parser.go.y:282
{
yyVAL.value = []*Pattern{yyDollar[1].value.(*Pattern)}
}
case 48:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:280
+//line parser.go.y:286
{
yyVAL.value = append(yyDollar[1].value.([]*Pattern), yyDollar[3].value.(*Pattern))
}
case 49:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:286
+//line parser.go.y:292
{
yyVAL.value = []*PatternObject{yyDollar[1].value.(*PatternObject)}
}
case 50:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:290
+//line parser.go.y:296
{
yyVAL.value = append(yyDollar[1].value.([]*PatternObject), yyDollar[3].value.(*PatternObject))
}
case 51:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:296
+//line parser.go.y:302
{
yyVAL.value = &PatternObject{Key: yyDollar[1].token, Val: yyDollar[3].value.(*Pattern)}
}
case 52:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:300
+//line parser.go.y:306
{
yyVAL.value = &PatternObject{KeyString: yyDollar[1].value.(*String), Val: yyDollar[3].value.(*Pattern)}
}
case 53:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:304
+//line parser.go.y:310
{
yyVAL.value = &PatternObject{KeyQuery: yyDollar[2].value.(*Query), Val: yyDollar[5].value.(*Pattern)}
}
case 54:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:308
+//line parser.go.y:314
{
- yyVAL.value = &PatternObject{KeyOnly: yyDollar[1].token}
+ yyVAL.value = &PatternObject{Key: yyDollar[1].token}
}
case 55:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:314
+//line parser.go.y:320
{
yyVAL.value = &Term{Type: TermTypeIdentity}
}
case 56:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:318
+//line parser.go.y:324
{
yyVAL.value = &Term{Type: TermTypeRecurse}
}
case 57:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:322
+//line parser.go.y:328
{
yyVAL.value = &Term{Type: TermTypeIndex, Index: &Index{Name: yyDollar[1].token}}
}
case 58:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:326
+//line parser.go.y:332
{
if yyDollar[2].value.(*Suffix).Iter {
yyVAL.value = &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{yyDollar[2].value.(*Suffix)}}
@@ -1157,569 +1169,569 @@ yydefault:
}
case 59:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:334
+//line parser.go.y:340
{
yyVAL.value = &Term{Type: TermTypeIndex, Index: &Index{Str: yyDollar[2].value.(*String)}}
}
case 60:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:338
+//line parser.go.y:344
{
yyVAL.value = &Term{Type: TermTypeNull}
}
case 61:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:342
+//line parser.go.y:348
{
yyVAL.value = &Term{Type: TermTypeTrue}
}
case 62:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:346
+//line parser.go.y:352
{
yyVAL.value = &Term{Type: TermTypeFalse}
}
case 63:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:350
+//line parser.go.y:356
{
yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token}}
}
case 64:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:354
+//line parser.go.y:360
{
yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token, Args: yyDollar[3].value.([]*Query)}}
}
case 65:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:358
+//line parser.go.y:364
{
yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token}}
}
case 66:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:362
+//line parser.go.y:368
{
yyVAL.value = &Term{Type: TermTypeNumber, Number: yyDollar[1].token}
}
case 67:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:366
+//line parser.go.y:372
{
yyVAL.value = &Term{Type: TermTypeFormat, Format: yyDollar[1].token}
}
case 68:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:370
+//line parser.go.y:376
{
yyVAL.value = &Term{Type: TermTypeFormat, Format: yyDollar[1].token, Str: yyDollar[2].value.(*String)}
}
case 69:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:374
+//line parser.go.y:380
{
yyVAL.value = &Term{Type: TermTypeString, Str: yyDollar[1].value.(*String)}
}
case 70:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:378
+//line parser.go.y:384
{
yyVAL.value = &Term{Type: TermTypeQuery, Query: yyDollar[2].value.(*Query)}
}
case 71:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:382
+//line parser.go.y:388
{
yyVAL.value = &Term{Type: TermTypeUnary, Unary: &Unary{OpAdd, yyDollar[2].value.(*Term)}}
}
case 72:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:386
+//line parser.go.y:392
{
yyVAL.value = &Term{Type: TermTypeUnary, Unary: &Unary{OpSub, yyDollar[2].value.(*Term)}}
}
case 73:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:390
+//line parser.go.y:396
{
yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{}}
}
case 74:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:394
+//line parser.go.y:400
{
yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{yyDollar[2].value.([]*ObjectKeyVal)}}
}
case 75:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:398
+//line parser.go.y:404
{
yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{yyDollar[2].value.([]*ObjectKeyVal)}}
}
case 76:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:402
+//line parser.go.y:408
{
yyVAL.value = &Term{Type: TermTypeArray, Array: &Array{}}
}
case 77:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:406
+//line parser.go.y:412
{
yyVAL.value = &Term{Type: TermTypeArray, Array: &Array{yyDollar[2].value.(*Query)}}
}
case 78:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:410
+//line parser.go.y:416
{
yyVAL.value = &Term{Type: TermTypeBreak, Break: yyDollar[2].token}
}
case 79:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:414
+//line parser.go.y:420
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Index: &Index{Name: yyDollar[2].token}})
}
case 80:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:418
+//line parser.go.y:424
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, yyDollar[2].value.(*Suffix))
}
case 81:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:422
+//line parser.go.y:428
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Optional: true})
}
case 82:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:426
+//line parser.go.y:432
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, yyDollar[3].value.(*Suffix))
}
case 83:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:430
+//line parser.go.y:436
{
yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Index: &Index{Str: yyDollar[3].value.(*String)}})
}
case 84:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:436
+//line parser.go.y:442
{
yyVAL.value = &String{Str: yyDollar[1].token}
}
case 85:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:440
+//line parser.go.y:446
{
yyVAL.value = &String{Queries: yyDollar[2].value.([]*Query)}
}
case 86:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:446
+//line parser.go.y:452
{
yyVAL.value = []*Query{}
}
case 87:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:450
+//line parser.go.y:456
{
yyVAL.value = append(yyDollar[1].value.([]*Query), &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: yyDollar[2].token}}})
}
case 88:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:454
+//line parser.go.y:460
{
yylex.(*lexer).inString = true
yyVAL.value = append(yyDollar[1].value.([]*Query), &Query{Term: &Term{Type: TermTypeQuery, Query: yyDollar[3].value.(*Query)}})
}
case 89:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:460
+//line parser.go.y:466
{
}
case 90:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:461
+//line parser.go.y:467
{
}
case 91:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:464
+//line parser.go.y:470
{
}
case 92:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:465
+//line parser.go.y:471
{
}
case 93:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:469
+//line parser.go.y:475
{
yyVAL.value = &Suffix{Iter: true}
}
case 94:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:473
+//line parser.go.y:479
{
yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query)}}
}
case 95:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:477
+//line parser.go.y:483
{
yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query), IsSlice: true}}
}
case 96:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:481
+//line parser.go.y:487
{
yyVAL.value = &Suffix{Index: &Index{End: yyDollar[3].value.(*Query), IsSlice: true}}
}
case 97:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:485
+//line parser.go.y:491
{
yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query), End: yyDollar[4].value.(*Query), IsSlice: true}}
}
case 98:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:491
+//line parser.go.y:497
{
yyVAL.value = []*Query{yyDollar[1].value.(*Query)}
}
case 99:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:495
+//line parser.go.y:501
{
yyVAL.value = append(yyDollar[1].value.([]*Query), yyDollar[3].value.(*Query))
}
case 100:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:501
+//line parser.go.y:507
{
yyVAL.value = []*IfElif(nil)
}
case 101:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:505
+//line parser.go.y:511
{
yyVAL.value = append(yyDollar[1].value.([]*IfElif), &IfElif{yyDollar[3].value.(*Query), yyDollar[5].value.(*Query)})
}
case 102:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:511
+//line parser.go.y:517
{
yyVAL.value = (*Query)(nil)
}
case 103:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:515
+//line parser.go.y:521
{
yyVAL.value = yyDollar[2].value
}
case 104:
yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:521
+//line parser.go.y:527
{
yyVAL.value = (*Query)(nil)
}
case 105:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:525
+//line parser.go.y:531
{
yyVAL.value = yyDollar[2].value
}
case 106:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:531
+//line parser.go.y:537
{
yyVAL.value = []*ObjectKeyVal{yyDollar[1].value.(*ObjectKeyVal)}
}
case 107:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:535
+//line parser.go.y:541
{
yyVAL.value = append(yyDollar[1].value.([]*ObjectKeyVal), yyDollar[3].value.(*ObjectKeyVal))
}
case 108:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:541
+//line parser.go.y:547
{
yyVAL.value = &ObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ObjectVal)}
}
case 109:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:545
+//line parser.go.y:551
{
yyVAL.value = &ObjectKeyVal{KeyString: yyDollar[1].value.(*String), Val: yyDollar[3].value.(*ObjectVal)}
}
case 110:
yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:549
+//line parser.go.y:555
{
yyVAL.value = &ObjectKeyVal{KeyQuery: yyDollar[2].value.(*Query), Val: yyDollar[5].value.(*ObjectVal)}
}
case 111:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:553
+//line parser.go.y:559
{
- yyVAL.value = &ObjectKeyVal{KeyOnly: yyDollar[1].token}
+ yyVAL.value = &ObjectKeyVal{Key: yyDollar[1].token}
}
case 112:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:557
+//line parser.go.y:563
{
- yyVAL.value = &ObjectKeyVal{KeyOnlyString: yyDollar[1].value.(*String)}
+ yyVAL.value = &ObjectKeyVal{KeyString: yyDollar[1].value.(*String)}
}
case 113:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:562
+//line parser.go.y:568
{
}
case 114:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:563
+//line parser.go.y:569
{
}
case 115:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:564
+//line parser.go.y:570
{
}
case 116:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:568
+//line parser.go.y:574
{
yyVAL.value = &ObjectVal{[]*Query{{Term: yyDollar[1].value.(*Term)}}}
}
case 117:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:572
+//line parser.go.y:578
{
yyVAL.value = &ObjectVal{append(yyDollar[1].value.(*ObjectVal).Queries, &Query{Term: yyDollar[3].value.(*Term)})}
}
case 118:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:578
+//line parser.go.y:584
{
yyVAL.value = &ConstTerm{Object: yyDollar[1].value.(*ConstObject)}
}
case 119:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:582
+//line parser.go.y:588
{
yyVAL.value = &ConstTerm{Array: yyDollar[1].value.(*ConstArray)}
}
case 120:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:586
+//line parser.go.y:592
{
yyVAL.value = &ConstTerm{Number: yyDollar[1].token}
}
case 121:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:590
+//line parser.go.y:596
{
yyVAL.value = &ConstTerm{Str: yyDollar[1].token}
}
case 122:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:594
+//line parser.go.y:600
{
yyVAL.value = &ConstTerm{Null: true}
}
case 123:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:598
+//line parser.go.y:604
{
yyVAL.value = &ConstTerm{True: true}
}
case 124:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:602
+//line parser.go.y:608
{
yyVAL.value = &ConstTerm{False: true}
}
case 125:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:608
+//line parser.go.y:614
{
yyVAL.value = &ConstObject{}
}
case 126:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:612
+//line parser.go.y:618
{
yyVAL.value = &ConstObject{yyDollar[2].value.([]*ConstObjectKeyVal)}
}
case 127:
yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:616
+//line parser.go.y:622
{
yyVAL.value = &ConstObject{yyDollar[2].value.([]*ConstObjectKeyVal)}
}
case 128:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:622
+//line parser.go.y:628
{
yyVAL.value = []*ConstObjectKeyVal{yyDollar[1].value.(*ConstObjectKeyVal)}
}
case 129:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:626
+//line parser.go.y:632
{
yyVAL.value = append(yyDollar[1].value.([]*ConstObjectKeyVal), yyDollar[3].value.(*ConstObjectKeyVal))
}
case 130:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:632
+//line parser.go.y:638
{
yyVAL.value = &ConstObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
}
case 131:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:636
+//line parser.go.y:642
{
yyVAL.value = &ConstObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
}
case 132:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:640
+//line parser.go.y:646
{
yyVAL.value = &ConstObjectKeyVal{KeyString: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
}
case 133:
yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:646
+//line parser.go.y:652
{
yyVAL.value = &ConstArray{}
}
case 134:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:650
+//line parser.go.y:656
{
yyVAL.value = &ConstArray{yyDollar[2].value.([]*ConstTerm)}
}
case 135:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:656
+//line parser.go.y:662
{
yyVAL.value = []*ConstTerm{yyDollar[1].value.(*ConstTerm)}
}
case 136:
yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:660
+//line parser.go.y:666
{
yyVAL.value = append(yyDollar[1].value.([]*ConstTerm), yyDollar[3].value.(*ConstTerm))
}
case 137:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:665
+//line parser.go.y:671
{
}
case 138:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:666
+//line parser.go.y:672
{
}
case 139:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:667
+//line parser.go.y:673
{
}
case 140:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:668
+//line parser.go.y:674
{
}
case 141:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:669
+//line parser.go.y:675
{
}
case 142:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:670
+//line parser.go.y:676
{
}
case 143:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:671
+//line parser.go.y:677
{
}
case 144:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:672
+//line parser.go.y:678
{
}
case 145:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:673
+//line parser.go.y:679
{
}
case 146:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:674
+//line parser.go.y:680
{
}
case 147:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:675
+//line parser.go.y:681
{
}
case 148:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:676
+//line parser.go.y:682
{
}
case 149:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:677
+//line parser.go.y:683
{
}
case 150:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:678
+//line parser.go.y:684
{
}
case 151:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:679
+//line parser.go.y:685
{
}
case 152:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:680
+//line parser.go.y:686
{
}
case 153:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:681
+//line parser.go.y:687
{
}
case 154:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:682
+//line parser.go.y:688
{
}
case 155:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:683
+//line parser.go.y:689
{
}
case 156:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:684
+//line parser.go.y:690
{
}
case 157:
yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:685
+//line parser.go.y:691
{
}
}
diff --git a/vendor/github.com/itchyny/gojq/parser.go.y b/vendor/github.com/itchyny/gojq/parser.go.y
index 5e2bc081..380c3cf6 100644
--- a/vendor/github.com/itchyny/gojq/parser.go.y
+++ b/vendor/github.com/itchyny/gojq/parser.go.y
@@ -1,7 +1,12 @@
%{
package gojq
-// Parse parses a query.
+// Parse a query string, and returns the query struct.
+//
+// If parsing failed, the returned error has the method Token() (string, int),
+// which reports the invalid token and the byte offset in the query string. The
+// token is empty if the error occurred after scanning the entire query string.
+// The byte offset is the scanned bytes when the error occurred.
func Parse(src string) (*Query, error) {
l := newLexer(src)
if yyParse(l) > 0 {
@@ -26,7 +31,7 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
%}
%union {
- value interface{}
+ value any
token string
operator Operator
}
@@ -41,11 +46,12 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
%token tokModule tokImport tokInclude tokDef tokAs tokLabel tokBreak
%token tokNull tokTrue tokFalse
%token tokIdent tokVariable tokModuleIdent tokModuleVariable
-%token tokIndex tokNumber tokFormat tokInvalid
+%token tokIndex tokNumber tokFormat
%token tokString tokStringStart tokStringQuery tokStringEnd
%token tokIf tokThen tokElif tokElse tokEnd
%token tokTry tokCatch tokReduce tokForeach
%token tokRecurse tokFuncDefPost tokTermPost tokEmptyCatch
+%token tokInvalid tokInvalidEscapeSequence tokUnterminatedString
%nonassoc tokFuncDefPost tokTermPost
%right '|'
@@ -306,7 +312,7 @@ objectpattern
}
| tokVariable
{
- $$ = &PatternObject{KeyOnly: $1}
+ $$ = &PatternObject{Key: $1}
}
term
@@ -551,11 +557,11 @@ objectkeyval
}
| objectkey
{
- $$ = &ObjectKeyVal{KeyOnly: $1}
+ $$ = &ObjectKeyVal{Key: $1}
}
| string
{
- $$ = &ObjectKeyVal{KeyOnlyString: $1.(*String)}
+ $$ = &ObjectKeyVal{KeyString: $1.(*String)}
}
objectkey
diff --git a/vendor/github.com/itchyny/gojq/preview.go b/vendor/github.com/itchyny/gojq/preview.go
new file mode 100644
index 00000000..e082eb56
--- /dev/null
+++ b/vendor/github.com/itchyny/gojq/preview.go
@@ -0,0 +1,77 @@
+package gojq
+
+import "unicode/utf8"
+
+// Preview returns the preview string of v. The preview string is basically the
+// same as the jq-flavored JSON encoding returned by [Marshal], but is truncated
+// by 30 bytes, and more efficient than truncating the result of [Marshal].
+//
+// This method is used by error messages of built-in operators and functions,
+// and accepts only limited types (nil, bool, int, float64, *big.Int, string,
+// []any, and map[string]any). Note that the maximum width and trailing strings
+// on truncation may be changed in the future.
+func Preview(v any) string {
+ bs := jsonLimitedMarshal(v, 32)
+ if l := 30; len(bs) > l {
+ var trailing string
+ switch v.(type) {
+ case string:
+ trailing = ` ..."`
+ case []any:
+ trailing = " ...]"
+ case map[string]any:
+ trailing = " ...}"
+ default:
+ trailing = " ..."
+ }
+ for len(bs) > l-len(trailing) {
+ _, size := utf8.DecodeLastRune(bs)
+ bs = bs[:len(bs)-size]
+ }
+ bs = append(bs, trailing...)
+ }
+ return string(bs)
+}
+
+func jsonLimitedMarshal(v any, n int) (bs []byte) {
+ w := &limitedWriter{buf: make([]byte, n)}
+ defer func() {
+ _ = recover()
+ bs = w.Bytes()
+ }()
+ (&encoder{w: w}).encode(v)
+ return
+}
+
+type limitedWriter struct {
+ buf []byte
+ off int
+}
+
+func (w *limitedWriter) Write(bs []byte) (int, error) {
+ n := copy(w.buf[w.off:], bs)
+ if w.off += n; w.off == len(w.buf) {
+ panic(struct{}{})
+ }
+ return n, nil
+}
+
+func (w *limitedWriter) WriteByte(b byte) error {
+ w.buf[w.off] = b
+ if w.off++; w.off == len(w.buf) {
+ panic(struct{}{})
+ }
+ return nil
+}
+
+func (w *limitedWriter) WriteString(s string) (int, error) {
+ n := copy(w.buf[w.off:], s)
+ if w.off += n; w.off == len(w.buf) {
+ panic(struct{}{})
+ }
+ return n, nil
+}
+
+func (w *limitedWriter) Bytes() []byte {
+ return w.buf[:w.off]
+}
diff --git a/vendor/github.com/itchyny/gojq/query.go b/vendor/github.com/itchyny/gojq/query.go
index 98b65027..5f20b4ff 100644
--- a/vendor/github.com/itchyny/gojq/query.go
+++ b/vendor/github.com/itchyny/gojq/query.go
@@ -2,8 +2,6 @@ package gojq
import (
"context"
- "encoding/json"
- "strconv"
"strings"
)
@@ -21,13 +19,14 @@ type Query struct {
// Run the query.
//
-// It is safe to call this method of a *Query in multiple goroutines.
-func (e *Query) Run(v interface{}) Iter {
+// It is safe to call this method in goroutines, to reuse a parsed [*Query].
+// But for arguments, do not give values sharing same data between goroutines.
+func (e *Query) Run(v any) Iter {
return e.RunWithContext(context.Background(), v)
}
// RunWithContext runs the query with context.
-func (e *Query) RunWithContext(ctx context.Context, v interface{}) Iter {
+func (e *Query) RunWithContext(ctx context.Context, v any) Iter {
code, err := Compile(e)
if err != nil {
return NewIter(err)
@@ -93,11 +92,18 @@ func (e *Query) minify() {
}
}
-func (e *Query) toIndices() []interface{} {
- if e.FuncDefs != nil || e.Right != nil || e.Term == nil {
+func (e *Query) toIndexKey() any {
+ if e.Term == nil {
return nil
}
- return e.Term.toIndices()
+ return e.Term.toIndexKey()
+}
+
+func (e *Query) toIndices(xs []any) []any {
+ if e.Term == nil {
+ return nil
+ }
+ return e.Term.toIndices(xs)
}
// Import ...
@@ -117,12 +123,12 @@ func (e *Import) String() string {
func (e *Import) writeTo(s *strings.Builder) {
if e.ImportPath != "" {
s.WriteString("import ")
- s.WriteString(strconv.Quote(e.ImportPath))
+ jsonEncodeString(s, e.ImportPath)
s.WriteString(" as ")
s.WriteString(e.ImportAlias)
} else {
s.WriteString("include ")
- s.WriteString(strconv.Quote(e.IncludePath))
+ jsonEncodeString(s, e.IncludePath)
}
if e.Meta != nil {
s.WriteByte(' ')
@@ -308,25 +314,48 @@ func (e *Term) toFunc() string {
}
}
-func (e *Term) toIndices() []interface{} {
- if e.Index != nil {
- xs := e.Index.toIndices()
- if xs == nil {
+func (e *Term) toIndexKey() any {
+ switch e.Type {
+ case TermTypeNumber:
+ return toNumber(e.Number)
+ case TermTypeUnary:
+ return e.Unary.toNumber()
+ case TermTypeString:
+ if e.Str.Queries == nil {
+ return e.Str.Str
+ }
+ return nil
+ default:
+ return nil
+ }
+}
+
+func (e *Term) toIndices(xs []any) []any {
+ switch e.Type {
+ case TermTypeIndex:
+ if xs = e.Index.toIndices(xs); xs == nil {
return nil
}
- for _, s := range e.SuffixList {
- x := s.toIndices()
- if x == nil {
- return nil
- }
- xs = append(xs, x...)
+ case TermTypeQuery:
+ if xs = e.Query.toIndices(xs); xs == nil {
+ return nil
}
- return xs
- } else if e.Query != nil && len(e.SuffixList) == 0 {
- return e.Query.toIndices()
- } else {
+ default:
return nil
}
+ for _, s := range e.SuffixList {
+ if xs = s.toIndices(xs); xs == nil {
+ return nil
+ }
+ }
+ return xs
+}
+
+func (e *Term) toNumber() any {
+ if e.Type == TermTypeNumber {
+ return toNumber(e.Number)
+ }
+ return nil
}
// Unary ...
@@ -350,6 +379,14 @@ func (e *Unary) minify() {
e.Term.minify()
}
+func (e *Unary) toNumber() any {
+ v := e.Term.toNumber()
+ if v != nil && e.Op == OpSub {
+ v = funcOpNegate(v)
+ }
+ return v
+}
+
// Pattern ...
type Pattern struct {
Name string
@@ -393,7 +430,6 @@ type PatternObject struct {
KeyString *String
KeyQuery *Query
Val *Pattern
- KeyOnly string
}
func (e *PatternObject) String() string {
@@ -416,9 +452,6 @@ func (e *PatternObject) writeTo(s *strings.Builder) {
s.WriteString(": ")
e.Val.writeTo(s)
}
- if e.KeyOnly != "" {
- s.WriteString(e.KeyOnly)
- }
}
// Index ...
@@ -450,24 +483,22 @@ func (e *Index) writeTo(s *strings.Builder) {
func (e *Index) writeSuffixTo(s *strings.Builder) {
if e.Name != "" {
s.WriteString(e.Name)
+ } else if e.Str != nil {
+ e.Str.writeTo(s)
} else {
- if e.Str != nil {
- e.Str.writeTo(s)
- } else {
- s.WriteByte('[')
- if e.IsSlice {
- if e.Start != nil {
- e.Start.writeTo(s)
- }
- s.WriteByte(':')
- if e.End != nil {
- e.End.writeTo(s)
- }
- } else {
+ s.WriteByte('[')
+ if e.IsSlice {
+ if e.Start != nil {
e.Start.writeTo(s)
}
- s.WriteByte(']')
+ s.WriteByte(':')
+ if e.End != nil {
+ e.End.writeTo(s)
+ }
+ } else {
+ e.Start.writeTo(s)
}
+ s.WriteByte(']')
}
}
@@ -483,11 +514,38 @@ func (e *Index) minify() {
}
}
-func (e *Index) toIndices() []interface{} {
- if e.Name == "" {
- return nil
+func (e *Index) toIndexKey() any {
+ if e.Name != "" {
+ return e.Name
+ } else if e.Str != nil {
+ if e.Str.Queries == nil {
+ return e.Str.Str
+ }
+ } else if !e.IsSlice {
+ return e.Start.toIndexKey()
+ } else {
+ var start, end any
+ ok := true
+ if e.Start != nil {
+ start = e.Start.toIndexKey()
+ ok = start != nil
+ }
+ if e.End != nil && ok {
+ end = e.End.toIndexKey()
+ ok = end != nil
+ }
+ if ok {
+ return map[string]any{"start": start, "end": end}
+ }
+ }
+ return nil
+}
+
+func (e *Index) toIndices(xs []any) []any {
+ if k := e.toIndexKey(); k != nil {
+ return append(xs, k)
}
- return []interface{}{e.Name}
+ return nil
}
// Func ...
@@ -543,7 +601,7 @@ func (e *String) String() string {
func (e *String) writeTo(s *strings.Builder) {
if e.Queries == nil {
- s.WriteString(strconv.Quote(e.Str))
+ jsonEncodeString(s, e.Str)
return
}
s.WriteByte('"')
@@ -599,12 +657,10 @@ func (e *Object) minify() {
// ObjectKeyVal ...
type ObjectKeyVal struct {
- Key string
- KeyString *String
- KeyQuery *Query
- Val *ObjectVal
- KeyOnly string
- KeyOnlyString *String
+ Key string
+ KeyString *String
+ KeyQuery *Query
+ Val *ObjectVal
}
func (e *ObjectKeyVal) String() string {
@@ -627,11 +683,6 @@ func (e *ObjectKeyVal) writeTo(s *strings.Builder) {
s.WriteString(": ")
e.Val.writeTo(s)
}
- if e.KeyOnly != "" {
- s.WriteString(e.KeyOnly)
- } else if e.KeyOnlyString != nil {
- e.KeyOnlyString.writeTo(s)
- }
}
func (e *ObjectKeyVal) minify() {
@@ -643,9 +694,6 @@ func (e *ObjectKeyVal) minify() {
if e.Val != nil {
e.Val.minify()
}
- if e.KeyOnlyString != nil {
- e.KeyOnlyString.minify()
- }
}
// ObjectVal ...
@@ -737,21 +785,21 @@ func (e *Suffix) minify() {
}
}
-func (e *Suffix) toTerm() (*Term, bool) {
+func (e *Suffix) toTerm() *Term {
if e.Index != nil {
- return &Term{Type: TermTypeIndex, Index: e.Index}, true
+ return &Term{Type: TermTypeIndex, Index: e.Index}
} else if e.Iter {
- return &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}, true
+ return &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}
} else {
- return nil, false
+ return nil
}
}
-func (e *Suffix) toIndices() []interface{} {
+func (e *Suffix) toIndices(xs []any) []any {
if e.Index == nil {
return nil
}
- return e.Index.toIndices()
+ return e.Index.toIndices(xs)
}
// Bind ...
@@ -1005,17 +1053,17 @@ func (e *ConstTerm) writeTo(s *strings.Builder) {
} else if e.False {
s.WriteString("false")
} else {
- s.WriteString(strconv.Quote(e.Str))
+ jsonEncodeString(s, e.Str)
}
}
-func (e *ConstTerm) toValue() interface{} {
+func (e *ConstTerm) toValue() any {
if e.Object != nil {
return e.Object.ToValue()
} else if e.Array != nil {
return e.Array.toValue()
} else if e.Number != "" {
- return normalizeNumber(json.Number(e.Number))
+ return toNumber(e.Number)
} else if e.Null {
return nil
} else if e.True {
@@ -1053,12 +1101,12 @@ func (e *ConstObject) writeTo(s *strings.Builder) {
s.WriteString(" }")
}
-// ToValue converts the object to map[string]interface{}.
-func (e *ConstObject) ToValue() map[string]interface{} {
+// ToValue converts the object to map[string]any.
+func (e *ConstObject) ToValue() map[string]any {
if e == nil {
return nil
}
- v := make(map[string]interface{}, len(e.KeyVals))
+ v := make(map[string]any, len(e.KeyVals))
for _, e := range e.KeyVals {
key := e.Key
if key == "" {
@@ -1114,8 +1162,8 @@ func (e *ConstArray) writeTo(s *strings.Builder) {
s.WriteByte(']')
}
-func (e *ConstArray) toValue() []interface{} {
- v := make([]interface{}, len(e.Elems))
+func (e *ConstArray) toValue() []any {
+ v := make([]any, len(e.Elems))
for i, e := range e.Elems {
v[i] = e.toValue()
}
diff --git a/vendor/github.com/itchyny/gojq/release.go b/vendor/github.com/itchyny/gojq/release.go
index 196fb772..c34dfb45 100644
--- a/vendor/github.com/itchyny/gojq/release.go
+++ b/vendor/github.com/itchyny/gojq/release.go
@@ -1,11 +1,11 @@
-//go:build !debug
-// +build !debug
+//go:build !gojq_debug
+// +build !gojq_debug
package gojq
type codeinfo struct{}
-func (c *compiler) appendCodeInfo(interface{}) {}
+func (c *compiler) appendCodeInfo(any) {}
func (c *compiler) deleteCodeInfo(string) {}
diff --git a/vendor/github.com/itchyny/gojq/scope_stack.go b/vendor/github.com/itchyny/gojq/scope_stack.go
index 82d620be..e140ca15 100644
--- a/vendor/github.com/itchyny/gojq/scope_stack.go
+++ b/vendor/github.com/itchyny/gojq/scope_stack.go
@@ -39,11 +39,12 @@ func (s *scopeStack) empty() bool {
return s.index < 0
}
-func (s *scopeStack) save(index, limit *int) {
- *index, *limit = s.index, s.limit
+func (s *scopeStack) save() (index, limit int) {
+ index, limit = s.index, s.limit
if s.index > s.limit {
s.limit = s.index
}
+ return
}
func (s *scopeStack) restore(index, limit int) {
diff --git a/vendor/github.com/itchyny/gojq/stack.go b/vendor/github.com/itchyny/gojq/stack.go
index f629d28e..a0e265c8 100644
--- a/vendor/github.com/itchyny/gojq/stack.go
+++ b/vendor/github.com/itchyny/gojq/stack.go
@@ -7,7 +7,7 @@ type stack struct {
}
type block struct {
- value interface{}
+ value any
next int
}
@@ -15,7 +15,7 @@ func newStack() *stack {
return &stack{index: -1, limit: -1}
}
-func (s *stack) push(v interface{}) {
+func (s *stack) push(v any) {
b := block{v, s.index}
i := s.index + 1
if i <= s.limit {
@@ -29,13 +29,13 @@ func (s *stack) push(v interface{}) {
}
}
-func (s *stack) pop() interface{} {
+func (s *stack) pop() any {
b := s.data[s.index]
s.index = b.next
return b.value
}
-func (s *stack) top() interface{} {
+func (s *stack) top() any {
return s.data[s.index].value
}
@@ -43,11 +43,12 @@ func (s *stack) empty() bool {
return s.index < 0
}
-func (s *stack) save(index, limit *int) {
- *index, *limit = s.index, s.limit
+func (s *stack) save() (index, limit int) {
+ index, limit = s.index, s.limit
if s.index > s.limit {
s.limit = s.index
}
+ return
}
func (s *stack) restore(index, limit int) {
diff --git a/vendor/github.com/itchyny/gojq/term_type.go b/vendor/github.com/itchyny/gojq/term_type.go
index 1670948c..941e7ba9 100644
--- a/vendor/github.com/itchyny/gojq/term_type.go
+++ b/vendor/github.com/itchyny/gojq/term_type.go
@@ -1,6 +1,6 @@
package gojq
-// TermType represents the type of Term.
+// TermType represents the type of [Term].
type TermType int
// TermType list.
@@ -27,7 +27,7 @@ const (
TermTypeQuery
)
-// GoString implements GoStringer.
+// GoString implements [fmt.GoStringer].
func (termType TermType) GoString() (str string) {
defer func() { str = "gojq." + str }()
switch termType {
diff --git a/vendor/github.com/itchyny/gojq/type.go b/vendor/github.com/itchyny/gojq/type.go
new file mode 100644
index 00000000..bb388e20
--- /dev/null
+++ b/vendor/github.com/itchyny/gojq/type.go
@@ -0,0 +1,29 @@
+package gojq
+
+import (
+ "fmt"
+ "math/big"
+)
+
+// TypeOf returns the jq-flavored type name of v.
+//
+// This method is used by built-in type/0 function, and accepts only limited
+// types (nil, bool, int, float64, *big.Int, string, []any, and map[string]any).
+func TypeOf(v any) string {
+ switch v.(type) {
+ case nil:
+ return "null"
+ case bool:
+ return "boolean"
+ case int, float64, *big.Int:
+ return "number"
+ case string:
+ return "string"
+ case []any:
+ return "array"
+ case map[string]any:
+ return "object"
+ default:
+ panic(fmt.Sprintf("invalid type: %[1]T (%[1]v)", v))
+ }
+}
diff --git a/vendor/github.com/itchyny/timefmt-go/CHANGELOG.md b/vendor/github.com/itchyny/timefmt-go/CHANGELOG.md
index 52b37d05..61a4e9dc 100644
--- a/vendor/github.com/itchyny/timefmt-go/CHANGELOG.md
+++ b/vendor/github.com/itchyny/timefmt-go/CHANGELOG.md
@@ -1,4 +1,11 @@
# Changelog
+## [v0.1.5](https://github.com/itchyny/timefmt-go/compare/v0.1.4..v0.1.5) (2022-12-01)
+* support parsing time zone offset with name using both `%z` and `%Z`
+
+## [v0.1.4](https://github.com/itchyny/timefmt-go/compare/v0.1.3..v0.1.4) (2022-09-01)
+* improve documents
+* drop support for Go 1.16
+
## [v0.1.3](https://github.com/itchyny/timefmt-go/compare/v0.1.2..v0.1.3) (2021-04-14)
* implement `ParseInLocation` for configuring the default location
diff --git a/vendor/github.com/itchyny/timefmt-go/LICENSE b/vendor/github.com/itchyny/timefmt-go/LICENSE
index 4d650fa8..84d6cb03 100644
--- a/vendor/github.com/itchyny/timefmt-go/LICENSE
+++ b/vendor/github.com/itchyny/timefmt-go/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2020,2021 itchyny
+Copyright (c) 2020-2022 itchyny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/itchyny/timefmt-go/Makefile b/vendor/github.com/itchyny/timefmt-go/Makefile
index bacef7bf..a87cb286 100644
--- a/vendor/github.com/itchyny/timefmt-go/Makefile
+++ b/vendor/github.com/itchyny/timefmt-go/Makefile
@@ -1,20 +1,19 @@
GOBIN ?= $(shell go env GOPATH)/bin
-export GO111MODULE=on
.PHONY: all
all: test
.PHONY: test
test:
- go test -v ./...
+ go test -v -race ./...
.PHONY: lint
-lint: $(GOBIN)/golint
+lint: $(GOBIN)/staticcheck
go vet ./...
- golint -set_exit_status ./...
+ staticcheck -checks all,-ST1000 ./...
-$(GOBIN)/golint:
- cd && go get golang.org/x/lint/golint
+$(GOBIN)/staticcheck:
+ go install honnef.co/go/tools/cmd/staticcheck@latest
.PHONY: clean
clean:
diff --git a/vendor/github.com/itchyny/timefmt-go/README.md b/vendor/github.com/itchyny/timefmt-go/README.md
index 078b1e1a..f01af961 100644
--- a/vendor/github.com/itchyny/timefmt-go/README.md
+++ b/vendor/github.com/itchyny/timefmt-go/README.md
@@ -1,7 +1,7 @@
# timefmt-go
[![CI Status](https://github.com/itchyny/timefmt-go/workflows/CI/badge.svg)](https://github.com/itchyny/timefmt-go/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/itchyny/timefmt-go)](https://goreportcard.com/report/github.com/itchyny/timefmt-go)
-[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/itchyny/timefmt-go/blob/main/LICENSE)
+[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/itchyny/timefmt-go/blob/main/LICENSE)
[![release](https://img.shields.io/github/release/itchyny/timefmt-go/all.svg)](https://github.com/itchyny/timefmt-go/releases)
[![pkg.go.dev](https://pkg.go.dev/badge/github.com/itchyny/timefmt-go)](https://pkg.go.dev/github.com/itchyny/timefmt-go)
@@ -35,14 +35,15 @@ func main() {
Please refer to [`man 3 strftime`](https://linux.die.net/man/3/strftime) and
[`man 3 strptime`](https://linux.die.net/man/3/strptime) for formatters.
+As an extension, `%f` directive is supported for zero-padded microseconds, which originates from Python.
Note that `E` and `O` modifier characters are not supported.
## Comparison to other libraries
- This library
- provides both formatting and parsing functions in pure Go language,
- - depends only on the Go standard libraries not to grows up the module file.
+ - depends only on the Go standard libraries not to grow up dependency.
- `Format` (`strftime`) implements glibc extensions including
- - width specifier like `%10A, %10B %2k:%M`,
+ - width specifier like `%6Y %10B %4Z` (limited to 1024 bytes),
- omitting padding modifier like `%-y-%-m-%-d`,
- space padding modifier like `%_y-%_m-%_d`,
- upper case modifier like `%^a %^b`,
diff --git a/vendor/github.com/itchyny/timefmt-go/format.go b/vendor/github.com/itchyny/timefmt-go/format.go
index 1d9b3672..eea976ee 100644
--- a/vendor/github.com/itchyny/timefmt-go/format.go
+++ b/vendor/github.com/itchyny/timefmt-go/format.go
@@ -1,6 +1,7 @@
package timefmt
import (
+ "math"
"strconv"
"time"
)
@@ -10,8 +11,7 @@ func Format(t time.Time, format string) string {
return string(AppendFormat(make([]byte, 0, 64), t, format))
}
-// AppendFormat appends formatted time to the bytes.
-// You can use this method to reduce allocations.
+// AppendFormat appends formatted time string to the buffer.
func AppendFormat(buf []byte, t time.Time, format string) []byte {
year, month, day := t.Date()
hour, min, sec := t.Clock()
@@ -74,7 +74,7 @@ func AppendFormat(buf []byte, t time.Time, format string) []byte {
b = format[i]
if b <= '9' && '0' <= b {
width = width*10 + int(b&0x0F)
- if width >= int((^uint(0)>>1)/10) {
+ if width >= math.MaxInt/10 {
width = maxWidth
}
} else {
diff --git a/vendor/github.com/itchyny/timefmt-go/parse.go b/vendor/github.com/itchyny/timefmt-go/parse.go
index 2d2b5f4d..83b0df2c 100644
--- a/vendor/github.com/itchyny/timefmt-go/parse.go
+++ b/vendor/github.com/itchyny/timefmt-go/parse.go
@@ -25,7 +25,7 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
}
}()
var j, century, yday, colons int
- var pm bool
+ var pm, hasZoneName, hasZoneOffset bool
var pending string
for i, l := 0, len(source); i < len(format); i++ {
if b := format[i]; b == '%' {
@@ -158,14 +158,14 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
hour, min, sec = t.Clock()
month = int(mon)
case 'f':
- var msec, k, d int
- if msec, k, err = parseNumber(source, j, 6, 'f'); err != nil {
+ var usec, k, d int
+ if usec, k, err = parseNumber(source, j, 6, 'f'); err != nil {
return
}
- nsec = msec * 1000
for j, d = k, k-j; d < 6; d++ {
- nsec *= 10
+ usec *= 10
}
+ nsec = usec * 1000
case 'Z':
k := j
for ; k < l; k++ {
@@ -178,7 +178,14 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
err = fmt.Errorf(`cannot parse %q with "%%Z"`, source[j:k])
return
}
- loc = t.Location()
+ if hasZoneOffset {
+ name, _ := t.Zone()
+ _, offset := locationZone(loc)
+ loc = time.FixedZone(name, offset)
+ } else {
+ loc = t.Location()
+ }
+ hasZoneName = true
j = k
case 'z':
if j >= l {
@@ -231,7 +238,12 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
j = k
}
}
- loc, colons = time.FixedZone("", sign*((hour*60+min)*60+sec)), 0
+ var name string
+ if hasZoneName {
+ name, _ = locationZone(loc)
+ }
+ loc, colons = time.FixedZone(name, sign*((hour*60+min)*60+sec)), 0
+ hasZoneOffset = true
case 'Z':
loc, colons, j = time.UTC, 0, j+1
default:
@@ -328,6 +340,10 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
return time.Date(year, time.Month(month), day, hour, min, sec, nsec, loc), nil
}
+func locationZone(loc *time.Location) (name string, offset int) {
+ return time.Date(2000, time.January, 1, 0, 0, 0, 0, loc).Zone()
+}
+
type parseFormatError byte
func (err parseFormatError) Error() string {
diff --git a/vendor/github.com/itchyny/timefmt-go/timefmt.go b/vendor/github.com/itchyny/timefmt-go/timefmt.go
new file mode 100644
index 00000000..45bf6ae9
--- /dev/null
+++ b/vendor/github.com/itchyny/timefmt-go/timefmt.go
@@ -0,0 +1,2 @@
+// Package timefmt provides functions for formatting and parsing date time strings.
+package timefmt
diff --git a/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go b/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
index 7ae7091f..88908773 100644
--- a/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
+++ b/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
@@ -3,7 +3,6 @@
package fuzzy
import (
- "bytes"
"unicode"
"unicode/utf8"
@@ -53,9 +52,12 @@ func MatchNormalizedFold(source, target string) bool {
}
func match(source, target string, transformer transform.Transformer) bool {
- source = stringTransform(source, transformer)
- target = stringTransform(target, transformer)
+ sourceT := stringTransform(source, transformer)
+ targetT := stringTransform(target, transformer)
+ return matchTransformed(sourceT, targetT)
+}
+func matchTransformed(source, target string) bool {
lenDiff := len(target) - len(source)
if lenDiff < 0 {
@@ -101,10 +103,13 @@ func FindNormalizedFold(source string, targets []string) []string {
}
func find(source string, targets []string, transformer transform.Transformer) []string {
+ sourceT := stringTransform(source, transformer)
+
var matches []string
for _, target := range targets {
- if match(source, target, transformer) {
+ targetT := stringTransform(target, transformer)
+ if matchTransformed(sourceT, targetT) {
matches = append(matches, target)
}
}
@@ -194,10 +199,13 @@ func RankFindNormalizedFold(source string, targets []string) Ranks {
}
func rankFind(source string, targets []string, transformer transform.Transformer) Ranks {
+ sourceT := stringTransform(source, transformer)
+
var r Ranks
for index, target := range targets {
- if match(source, target, transformer) {
+ targetT := stringTransform(target, transformer)
+ if matchTransformed(sourceT, targetT) {
distance := LevenshteinDistance(source, target)
r = append(r, Rank{source, target, distance, index})
}
@@ -251,19 +259,30 @@ func stringTransform(s string, t transform.Transformer) (transformed string) {
type unicodeFoldTransformer struct{ transform.NopResetter }
func (unicodeFoldTransformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- runes := bytes.Runes(src)
- var lowerRunes []rune
- for _, r := range runes {
- lowerRunes = append(lowerRunes, unicode.ToLower(r))
- }
-
- srcBytes := []byte(string(lowerRunes))
- n := copy(dst, srcBytes)
- if n < len(srcBytes) {
- err = transform.ErrShortDst
+ // Converting src to a string allocates.
+ // In theory, it need not; see https://go.dev/issue/27148.
+ // It is possible to write this loop using utf8.DecodeRune
+ // and thereby avoid allocations, but it is noticeably slower.
+ // So just let's wait for the compiler to get smarter.
+ for _, r := range string(src) {
+ if r == utf8.RuneError {
+ // Go spec for ranging over a string says:
+ // If the iteration encounters an invalid UTF-8 sequence,
+ // the second value will be 0xFFFD, the Unicode replacement character,
+ // and the next iteration will advance a single byte in the string.
+ nSrc++
+ } else {
+ nSrc += utf8.RuneLen(r)
+ }
+ r = unicode.ToLower(r)
+ x := utf8.RuneLen(r)
+ if x > len(dst[nDst:]) {
+ err = transform.ErrShortDst
+ break
+ }
+ nDst += utf8.EncodeRune(dst[nDst:], r)
}
-
- return n, n, err
+ return nDst, nSrc, err
}
type nopTransformer struct{ transform.NopResetter }
diff --git a/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go b/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
index 4fb5838c..c0fc1910 100644
--- a/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
+++ b/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
@@ -33,11 +33,13 @@ func LevenshteinDistance(s, t string) int {
return column[len(r1)]
}
-func min(a, b, c int) int {
- if a < b && a < c {
+func min2(a, b int) int {
+ if a < b {
return a
- } else if b < c {
- return b
}
- return c
+ return b
+}
+
+func min(a, b, c int) int {
+ return min2(min2(a, b), c)
}
diff --git a/vendor/github.com/logrusorgru/aurora/.gitignore b/vendor/github.com/logrusorgru/aurora/.gitignore
deleted file mode 100644
index dbcb7cc7..00000000
--- a/vendor/github.com/logrusorgru/aurora/.gitignore
+++ /dev/null
@@ -1,34 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-*.out
-
-# coverage
-
-cover.html
-
-# benchcmp
-
-*.cmp
-
diff --git a/vendor/github.com/logrusorgru/aurora/.travis.yml b/vendor/github.com/logrusorgru/aurora/.travis.yml
deleted file mode 100644
index 570e361b..00000000
--- a/vendor/github.com/logrusorgru/aurora/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-go:
- - tip
-before_install:
- - go get github.com/axw/gocov/gocov
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
-script:
- - $HOME/gopath/bin/goveralls -service=travis-ci
diff --git a/vendor/github.com/logrusorgru/aurora/AUTHORS.md b/vendor/github.com/logrusorgru/aurora/AUTHORS.md
deleted file mode 100644
index 0ee9e3eb..00000000
--- a/vendor/github.com/logrusorgru/aurora/AUTHORS.md
+++ /dev/null
@@ -1,8 +0,0 @@
-AUTHORS
-=======
-
-- Konstantin Ivanov @logrusorgru
-- Mattias Eriksson @snaggen
-- Ousmane Traore @otraore
-- Simon Legner @simon04
-- Sevenate @sevenate
diff --git a/vendor/github.com/logrusorgru/aurora/CHANGELOG.md b/vendor/github.com/logrusorgru/aurora/CHANGELOG.md
deleted file mode 100644
index ad0a2025..00000000
--- a/vendor/github.com/logrusorgru/aurora/CHANGELOG.md
+++ /dev/null
@@ -1,59 +0,0 @@
-Changes
-=======
-
----
-16:05:02
-Thursday, July 2, 2020
-
-Change license from the WTFPL to the Unlicense due to pkg.go.dev restriction.
-
----
-15:39:40
-Wednesday, April 17, 2019
-
-- Bright background and foreground colors
-- 8-bit indexed colors `Index`, `BgIndex`
-- 24 grayscale colors `Gray`, `BgGray`
-- `Yellow` and `BgYellow` methods, mark Brow and BgBrown as deprecated
- Following specifications, correct name of the colors are yellow, but
- by historical reason they are called brown. Both, the `Yellow` and the
- `Brown` methods (including `Bg+`) represents the same colors. The Brown
- are leaved for backward compatibility until Go modules production release.
-- Additional formats
- + `Faint` that is opposite to the `Bold`
- + `DoublyUnderline`
- + `Fraktur`
- + `Italic`
- + `Underline`
- + `SlowBlink` with `Blink` alias
- + `RapidBlink`
- + `Reverse` that is alias for the `Inverse`
- + `Conceal` with `Hidden` alias
- + `CrossedOut` with `StrikeThrough` alias
- + `Framed`
- + `Encircled`
- + `Overlined`
-- Add AUTHORS.md file and change all copyright notices.
-- `Reset` method to create clear value. `Reset` method that replaces
- `Bleach` method. The `Bleach` method was marked as deprecated.
-
----
-
-14:25:49
-Friday, August 18, 2017
-
-- LICENSE.md changed to LICENSE
-- fix email in README.md
-- add "no warranty" to README.md
-- set proper copyright date
-
----
-
-16:59:28
-Tuesday, November 8, 2016
-
-- Rid out off sync.Pool
-- Little optimizations (very little)
-- Improved benchmarks
-
----
diff --git a/vendor/github.com/logrusorgru/aurora/LICENSE b/vendor/github.com/logrusorgru/aurora/LICENSE
deleted file mode 100644
index 68a49daa..00000000
--- a/vendor/github.com/logrusorgru/aurora/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-This is free and unencumbered software released into the public domain.
-
-Anyone is free to copy, modify, publish, use, compile, sell, or
-distribute this software, either in source code form or as a compiled
-binary, for any purpose, commercial or non-commercial, and by any
-means.
-
-In jurisdictions that recognize copyright laws, the author or authors
-of this software dedicate any and all copyright interest in the
-software to the public domain. We make this dedication for the benefit
-of the public at large and to the detriment of our heirs and
-successors. We intend this dedication to be an overt act of
-relinquishment in perpetuity of all present and future rights to this
-software under copyright law.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-For more information, please refer to
diff --git a/vendor/github.com/logrusorgru/aurora/README.md b/vendor/github.com/logrusorgru/aurora/README.md
deleted file mode 100644
index e0afce1c..00000000
--- a/vendor/github.com/logrusorgru/aurora/README.md
+++ /dev/null
@@ -1,314 +0,0 @@
-Aurora
-======
-
-[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/logrusorgru/aurora?tab=doc)
-[![Unlicense](https://img.shields.io/badge/license-unlicense-blue.svg)](http://unlicense.org/)
-[![Build Status](https://travis-ci.org/logrusorgru/aurora.svg)](https://travis-ci.org/logrusorgru/aurora)
-[![Coverage Status](https://coveralls.io/repos/logrusorgru/aurora/badge.svg?branch=master)](https://coveralls.io/r/logrusorgru/aurora?branch=master)
-[![GoReportCard](https://goreportcard.com/badge/logrusorgru/aurora)](https://goreportcard.com/report/logrusorgru/aurora)
-[![Gitter](https://img.shields.io/badge/chat-on_gitter-46bc99.svg?logo=data:image%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNCI%2BPGcgZmlsbD0iI2ZmZiI%2BPHJlY3QgeD0iMCIgeT0iMyIgd2lkdGg9IjEiIGhlaWdodD0iNSIvPjxyZWN0IHg9IjIiIHk9IjQiIHdpZHRoPSIxIiBoZWlnaHQ9IjciLz48cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMSIgaGVpZ2h0PSI3Ii8%2BPHJlY3QgeD0iNiIgeT0iNCIgd2lkdGg9IjEiIGhlaWdodD0iNCIvPjwvZz48L3N2Zz4%3D&logoWidth=10)](https://gitter.im/logrusorgru/aurora)
-
-Ultimate ANSI colors for Golang. The package supports Printf/Sprintf etc.
-
-
-![aurora logo](https://github.com/logrusorgru/aurora/blob/master/gopher_aurora.png)
-
-# TOC
-
-- [Installation](#installation)
-- [Usage](#usage)
- + [Simple](#simple)
- + [Printf](#printf)
- + [aurora.Sprintf](#aurorasprintf)
- + [Enable/Disable colors](#enabledisable-colors)
-- [Chains](#chains)
-- [Colorize](#colorize)
-- [Grayscale](#grayscale)
-- [8-bit colors](#8-bit-colors)
-- [Supported Colors & Formats](#supported-colors--formats)
- + [All colors](#all-colors)
- + [Standard and bright colors](#standard-and-bright-colors)
- + [Formats are likely supported](#formats-are-likely-supported)
- + [Formats are likely unsupported](#formats-are-likely-unsupported)
-- [Limitations](#limitations)
- + [Windows](#windows)
- + [TTY](#tty)
-- [Licensing](#licensing)
-
-# Installation
-
-Get
-```
-go get -u github.com/logrusorgru/aurora
-```
-Test
-```
-go test -cover github.com/logrusorgru/aurora
-```
-
-# Usage
-
-### Simple
-
-```go
-package main
-
-import (
- "fmt"
-
- . "github.com/logrusorgru/aurora"
-)
-
-func main() {
- fmt.Println("Hello,", Magenta("Aurora"))
- fmt.Println(Bold(Cyan("Cya!")))
-}
-
-```
-
-![simple png](https://github.com/logrusorgru/aurora/blob/master/simple.png)
-
-### Printf
-
-```go
-package main
-
-import (
- "fmt"
-
- . "github.com/logrusorgru/aurora"
-)
-
-func main() {
- fmt.Printf("Got it %d times\n", Green(1240))
- fmt.Printf("PI is %+1.2e\n", Cyan(3.14))
-}
-
-```
-
-![printf png](https://github.com/logrusorgru/aurora/blob/master/printf.png)
-
-### aurora.Sprintf
-
-```go
-package main
-
-import (
- "fmt"
-
- . "github.com/logrusorgru/aurora"
-)
-
-func main() {
- fmt.Println(Sprintf(Magenta("Got it %d times"), Green(1240)))
-}
-
-```
-
-![sprintf png](https://github.com/logrusorgru/aurora/blob/master/sprintf.png)
-
-### Enable/Disable colors
-
-```go
-package main
-
-import (
- "fmt"
- "flag"
-
- "github.com/logrusorgru/aurora"
-)
-
-// colorizer
-var au aurora.Aurora
-
-var colors = flag.Bool("colors", false, "enable or disable colors")
-
-func init() {
- flag.Parse()
- au = aurora.NewAurora(*colors)
-}
-
-func main() {
- // use colorizer
- fmt.Println(au.Green("Hello"))
-}
-
-```
-Without flags:
-![disable png](https://github.com/logrusorgru/aurora/blob/master/disable.png)
-
-With `-colors` flag:
-![enable png](https://github.com/logrusorgru/aurora/blob/master/enable.png)
-
-# Chains
-
-The following samples are equal
-
-```go
-x := BgMagenta(Bold(Red("x")))
-```
-
-```go
-x := Red("x").Bold().BgMagenta()
-```
-
-The second is more readable
-
-# Colorize
-
-There is `Colorize` function that allows to choose some colors and
-format from a side
-
-```go
-
-func getColors() Color {
- // some stuff that returns appropriate colors and format
-}
-
-// [...]
-
-func main() {
- fmt.Println(Colorize("Greeting", getColors()))
-}
-
-```
-Less complicated example
-
-```go
-x := Colorize("Greeting", GreenFg|GrayBg|BoldFm)
-```
-
-Unlike other color functions and methods (such as Red/BgBlue etc)
-a `Colorize` clears previous colors
-
-```go
-x := Red("x").Colorize(BgGreen) // will be with green background only
-```
-
-# Grayscale
-
-```go
-fmt.Println(" ",
- Gray(1-1, " 00-23 ").BgGray(24-1),
- Gray(4-1, " 03-19 ").BgGray(20-1),
- Gray(8-1, " 07-15 ").BgGray(16-1),
- Gray(12-1, " 11-11 ").BgGray(12-1),
- Gray(16-1, " 15-07 ").BgGray(8-1),
- Gray(20-1, " 19-03 ").BgGray(4-1),
- Gray(24-1, " 23-00 ").BgGray(1-1),
-)
-```
-
-![grayscale png](https://github.com/logrusorgru/aurora/blob/master/aurora_grayscale.png)
-
-# 8-bit colors
-
-Methods `Index` and `BgIndex` implements 8-bit colors.
-
-| Index/BgIndex | Meaning | Foreground | Background |
-| -------------- | --------------- | ---------- | ---------- |
-| 0- 7 | standard colors | 30- 37 | 40- 47 |
-| 8- 15 | bright colors | 90- 97 | 100-107 |
-| 16-231 | 216 colors | 38;5;n | 48;5;n |
-| 232-255 | 24 grayscale | 38;5;n | 48;5;n |
-
-
-# Supported colors & formats
-
-- formats
- + bold (1)
- + faint (2)
- + doubly-underline (21)
- + fraktur (20)
- + italic (3)
- + underline (4)
- + slow blink (5)
- + rapid blink (6)
- + reverse video (7)
- + conceal (8)
- + crossed out (9)
- + framed (51)
- + encircled (52)
- + overlined (53)
-- background and foreground colors, including bright
- + black
- + red
- + green
- + yellow (brown)
- + blue
- + magenta
- + cyan
- + white
- + 24 grayscale colors
- + 216 8-bit colors
-
-### All colors
-
-![linux png](https://github.com/logrusorgru/aurora/blob/master/aurora_colors_black.png)
-![white png](https://github.com/logrusorgru/aurora/blob/master/aurora_colors_white.png)
-
-### Standard and bright colors
-
-![linux black standard png](https://github.com/logrusorgru/aurora/blob/master/aurora_black_standard.png)
-![linux white standard png](https://github.com/logrusorgru/aurora/blob/master/aurora_white_standard.png)
-
-### Formats are likely supported
-
-![formats supported gif](https://github.com/logrusorgru/aurora/blob/master/aurora_formats.gif)
-
-### Formats are likely unsupported
-
-![formats rarely supported png](https://github.com/logrusorgru/aurora/blob/master/aurora_rarely_supported.png)
-
-# Limitations
-
-There is no way to represent `%T` and `%p` with colors using
-a standard approach
-
-```go
-package main
-
-import (
- "fmt"
-
- . "github.com/logrusorgru/aurora"
-)
-
-func main() {
- r := Red("red")
- var i int
- fmt.Printf("%T %p\n", r, Green(&i))
-}
-```
-
-Output will be without colors
-
-```
-aurora.value %!p(aurora.value={0xc42000a310 768 0})
-```
-
-The obvious workaround is `Red(fmt.Sprintf("%T", some))`
-
-### Windows
-
-The Aurora provides ANSI colors only, so there is no support for Windows. That said, there are workarounds available.
-Check out these comments to learn more:
-
-- [Using go-colorable](https://github.com/logrusorgru/aurora/issues/2#issuecomment-299014211).
-- [Using registry for Windows 10](https://github.com/logrusorgru/aurora/issues/10#issue-476361247).
-
-### TTY
-
-The Aurora has no internal TTY detectors by design. Take a look
- [this comment](https://github.com/logrusorgru/aurora/issues/2#issuecomment-299030108) if you want turn
-on colors for a terminal only, and turn them off for a file.
-
-### Licensing
-
-Copyright © 2016-2020 The Aurora Authors. This work is free.
-It comes without any warranty, to the extent permitted by applicable
-law. You can redistribute it and/or modify it under the terms of the
-the Unlicense. See the LICENSE file for more details.
-
-
diff --git a/vendor/github.com/logrusorgru/aurora/aurora.go b/vendor/github.com/logrusorgru/aurora/aurora.go
deleted file mode 100644
index 3b302305..00000000
--- a/vendor/github.com/logrusorgru/aurora/aurora.go
+++ /dev/null
@@ -1,725 +0,0 @@
-//
-// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
-// This program is free software. It comes without any warranty,
-// to the extent permitted by applicable law. You can redistribute
-// it and/or modify it under the terms of the Unlicense. See LICENSE
-// file for more details or see below.
-//
-
-//
-// This is free and unencumbered software released into the public domain.
-//
-// Anyone is free to copy, modify, publish, use, compile, sell, or
-// distribute this software, either in source code form or as a compiled
-// binary, for any purpose, commercial or non-commercial, and by any
-// means.
-//
-// In jurisdictions that recognize copyright laws, the author or authors
-// of this software dedicate any and all copyright interest in the
-// software to the public domain. We make this dedication for the benefit
-// of the public at large and to the detriment of our heirs and
-// successors. We intend this dedication to be an overt act of
-// relinquishment in perpetuity of all present and future rights to this
-// software under copyright law.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// For more information, please refer to
-//
-
-// Package aurora implements ANSI-colors
-package aurora
-
-import (
- "fmt"
-)
-
-// An Aurora implements colorizer interface.
-// It also can be a non-colorizer
-type Aurora interface {
-
- // Reset wraps given argument returning Value
- // without formats and colors.
- Reset(arg interface{}) Value
-
- //
- // Formats
- //
- //
- // Bold or increased intensity (1).
- Bold(arg interface{}) Value
- // Faint, decreased intensity (2).
- Faint(arg interface{}) Value
- //
- // DoublyUnderline or Bold off, double-underline
- // per ECMA-48 (21).
- DoublyUnderline(arg interface{}) Value
- // Fraktur, rarely supported (20).
- Fraktur(arg interface{}) Value
- //
- // Italic, not widely supported, sometimes
- // treated as inverse (3).
- Italic(arg interface{}) Value
- // Underline (4).
- Underline(arg interface{}) Value
- //
- // SlowBlink, blinking less than 150
- // per minute (5).
- SlowBlink(arg interface{}) Value
- // RapidBlink, blinking 150+ per minute,
- // not widely supported (6).
- RapidBlink(arg interface{}) Value
- // Blink is alias for the SlowBlink.
- Blink(arg interface{}) Value
- //
- // Reverse video, swap foreground and
- // background colors (7).
- Reverse(arg interface{}) Value
- // Inverse is alias for the Reverse
- Inverse(arg interface{}) Value
- //
- // Conceal, hidden, not widely supported (8).
- Conceal(arg interface{}) Value
- // Hidden is alias for the Conceal
- Hidden(arg interface{}) Value
- //
- // CrossedOut, characters legible, but
- // marked for deletion (9).
- CrossedOut(arg interface{}) Value
- // StrikeThrough is alias for the CrossedOut.
- StrikeThrough(arg interface{}) Value
- //
- // Framed (51).
- Framed(arg interface{}) Value
- // Encircled (52).
- Encircled(arg interface{}) Value
- //
- // Overlined (53).
- Overlined(arg interface{}) Value
-
- //
- // Foreground colors
- //
- //
- // Black foreground color (30)
- Black(arg interface{}) Value
- // Red foreground color (31)
- Red(arg interface{}) Value
- // Green foreground color (32)
- Green(arg interface{}) Value
- // Yellow foreground color (33)
- Yellow(arg interface{}) Value
- // Brown foreground color (33)
- //
- // Deprecated: use Yellow instead, following specification
- Brown(arg interface{}) Value
- // Blue foreground color (34)
- Blue(arg interface{}) Value
- // Magenta foreground color (35)
- Magenta(arg interface{}) Value
- // Cyan foreground color (36)
- Cyan(arg interface{}) Value
- // White foreground color (37)
- White(arg interface{}) Value
- //
- // Bright foreground colors
- //
- // BrightBlack foreground color (90)
- BrightBlack(arg interface{}) Value
- // BrightRed foreground color (91)
- BrightRed(arg interface{}) Value
- // BrightGreen foreground color (92)
- BrightGreen(arg interface{}) Value
- // BrightYellow foreground color (93)
- BrightYellow(arg interface{}) Value
- // BrightBlue foreground color (94)
- BrightBlue(arg interface{}) Value
- // BrightMagenta foreground color (95)
- BrightMagenta(arg interface{}) Value
- // BrightCyan foreground color (96)
- BrightCyan(arg interface{}) Value
- // BrightWhite foreground color (97)
- BrightWhite(arg interface{}) Value
- //
- // Other
- //
- // Index of pre-defined 8-bit foreground color
- // from 0 to 255 (38;5;n).
- //
- // 0- 7: standard colors (as in ESC [ 30–37 m)
- // 8- 15: high intensity colors (as in ESC [ 90–97 m)
- // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
- // 232-255: grayscale from black to white in 24 steps
- //
- Index(n uint8, arg interface{}) Value
- // Gray from 0 to 23.
- Gray(n uint8, arg interface{}) Value
-
- //
- // Background colors
- //
- //
- // BgBlack background color (40)
- BgBlack(arg interface{}) Value
- // BgRed background color (41)
- BgRed(arg interface{}) Value
- // BgGreen background color (42)
- BgGreen(arg interface{}) Value
- // BgYellow background color (43)
- BgYellow(arg interface{}) Value
- // BgBrown background color (43)
- //
- // Deprecated: use BgYellow instead, following specification
- BgBrown(arg interface{}) Value
- // BgBlue background color (44)
- BgBlue(arg interface{}) Value
- // BgMagenta background color (45)
- BgMagenta(arg interface{}) Value
- // BgCyan background color (46)
- BgCyan(arg interface{}) Value
- // BgWhite background color (47)
- BgWhite(arg interface{}) Value
- //
- // Bright background colors
- //
- // BgBrightBlack background color (100)
- BgBrightBlack(arg interface{}) Value
- // BgBrightRed background color (101)
- BgBrightRed(arg interface{}) Value
- // BgBrightGreen background color (102)
- BgBrightGreen(arg interface{}) Value
- // BgBrightYellow background color (103)
- BgBrightYellow(arg interface{}) Value
- // BgBrightBlue background color (104)
- BgBrightBlue(arg interface{}) Value
- // BgBrightMagenta background color (105)
- BgBrightMagenta(arg interface{}) Value
- // BgBrightCyan background color (106)
- BgBrightCyan(arg interface{}) Value
- // BgBrightWhite background color (107)
- BgBrightWhite(arg interface{}) Value
- //
- // Other
- //
- // BgIndex of 8-bit pre-defined background color
- // from 0 to 255 (48;5;n).
- //
- // 0- 7: standard colors (as in ESC [ 40–47 m)
- // 8- 15: high intensity colors (as in ESC [100–107 m)
- // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
- // 232-255: grayscale from black to white in 24 steps
- //
- BgIndex(n uint8, arg interface{}) Value
- // BgGray from 0 to 23.
- BgGray(n uint8, arg interface{}) Value
-
- //
- // Special
- //
- // Colorize removes existing colors and
- // formats of the argument and applies given.
- Colorize(arg interface{}, color Color) Value
-
- //
- // Support methods
- //
- // Sprintf allows to use colored format.
- Sprintf(format interface{}, args ...interface{}) string
-}
-
-// NewAurora returns a new Aurora interface that
-// will support or not support colors depending
-// the enableColors argument
-func NewAurora(enableColors bool) Aurora {
- if enableColors {
- return aurora{}
- }
- return auroraClear{}
-}
-
-// no colors
-
-type auroraClear struct{}
-
-func (auroraClear) Reset(arg interface{}) Value { return valueClear{arg} }
-
-func (auroraClear) Bold(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Faint(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) DoublyUnderline(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Fraktur(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Italic(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Underline(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) SlowBlink(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) RapidBlink(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Blink(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Reverse(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Inverse(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Conceal(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Hidden(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) CrossedOut(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) StrikeThrough(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Framed(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Encircled(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Overlined(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Black(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Red(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Green(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Yellow(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Brown(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Blue(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Magenta(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Cyan(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) White(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightBlack(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightRed(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightGreen(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightYellow(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightBlue(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightMagenta(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightCyan(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BrightWhite(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Index(_ uint8, arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Gray(_ uint8, arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBlack(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgRed(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgGreen(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgYellow(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrown(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBlue(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgMagenta(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgCyan(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgWhite(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightBlack(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightRed(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightGreen(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightYellow(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightBlue(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightMagenta(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightCyan(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgBrightWhite(arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgIndex(_ uint8, arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) BgGray(_ uint8, arg interface{}) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Colorize(arg interface{}, _ Color) Value {
- return valueClear{arg}
-}
-
-func (auroraClear) Sprintf(format interface{}, args ...interface{}) string {
- if str, ok := format.(string); ok {
- return fmt.Sprintf(str, args...)
- }
- return fmt.Sprintf(fmt.Sprint(format), args...)
-}
-
-// colorized
-
-type aurora struct{}
-
-func (aurora) Reset(arg interface{}) Value {
- return Reset(arg)
-}
-
-func (aurora) Bold(arg interface{}) Value {
- return Bold(arg)
-}
-
-func (aurora) Faint(arg interface{}) Value {
- return Faint(arg)
-}
-
-func (aurora) DoublyUnderline(arg interface{}) Value {
- return DoublyUnderline(arg)
-}
-
-func (aurora) Fraktur(arg interface{}) Value {
- return Fraktur(arg)
-}
-
-func (aurora) Italic(arg interface{}) Value {
- return Italic(arg)
-}
-
-func (aurora) Underline(arg interface{}) Value {
- return Underline(arg)
-}
-
-func (aurora) SlowBlink(arg interface{}) Value {
- return SlowBlink(arg)
-}
-
-func (aurora) RapidBlink(arg interface{}) Value {
- return RapidBlink(arg)
-}
-
-func (aurora) Blink(arg interface{}) Value {
- return Blink(arg)
-}
-
-func (aurora) Reverse(arg interface{}) Value {
- return Reverse(arg)
-}
-
-func (aurora) Inverse(arg interface{}) Value {
- return Inverse(arg)
-}
-
-func (aurora) Conceal(arg interface{}) Value {
- return Conceal(arg)
-}
-
-func (aurora) Hidden(arg interface{}) Value {
- return Hidden(arg)
-}
-
-func (aurora) CrossedOut(arg interface{}) Value {
- return CrossedOut(arg)
-}
-
-func (aurora) StrikeThrough(arg interface{}) Value {
- return StrikeThrough(arg)
-}
-
-func (aurora) Framed(arg interface{}) Value {
- return Framed(arg)
-}
-
-func (aurora) Encircled(arg interface{}) Value {
- return Encircled(arg)
-}
-
-func (aurora) Overlined(arg interface{}) Value {
- return Overlined(arg)
-}
-
-func (aurora) Black(arg interface{}) Value {
- return Black(arg)
-}
-
-func (aurora) Red(arg interface{}) Value {
- return Red(arg)
-}
-
-func (aurora) Green(arg interface{}) Value {
- return Green(arg)
-}
-
-func (aurora) Yellow(arg interface{}) Value {
- return Yellow(arg)
-}
-
-func (aurora) Brown(arg interface{}) Value {
- return Brown(arg)
-}
-
-func (aurora) Blue(arg interface{}) Value {
- return Blue(arg)
-}
-
-func (aurora) Magenta(arg interface{}) Value {
- return Magenta(arg)
-}
-
-func (aurora) Cyan(arg interface{}) Value {
- return Cyan(arg)
-}
-
-func (aurora) White(arg interface{}) Value {
- return White(arg)
-}
-
-func (aurora) BrightBlack(arg interface{}) Value {
- return BrightBlack(arg)
-}
-
-func (aurora) BrightRed(arg interface{}) Value {
- return BrightRed(arg)
-}
-
-func (aurora) BrightGreen(arg interface{}) Value {
- return BrightGreen(arg)
-}
-
-func (aurora) BrightYellow(arg interface{}) Value {
- return BrightYellow(arg)
-}
-
-func (aurora) BrightBlue(arg interface{}) Value {
- return BrightBlue(arg)
-}
-
-func (aurora) BrightMagenta(arg interface{}) Value {
- return BrightMagenta(arg)
-}
-
-func (aurora) BrightCyan(arg interface{}) Value {
- return BrightCyan(arg)
-}
-
-func (aurora) BrightWhite(arg interface{}) Value {
- return BrightWhite(arg)
-}
-
-func (aurora) Index(index uint8, arg interface{}) Value {
- return Index(index, arg)
-}
-
-func (aurora) Gray(n uint8, arg interface{}) Value {
- return Gray(n, arg)
-}
-
-func (aurora) BgBlack(arg interface{}) Value {
- return BgBlack(arg)
-}
-
-func (aurora) BgRed(arg interface{}) Value {
- return BgRed(arg)
-}
-
-func (aurora) BgGreen(arg interface{}) Value {
- return BgGreen(arg)
-}
-
-func (aurora) BgYellow(arg interface{}) Value {
- return BgYellow(arg)
-}
-
-func (aurora) BgBrown(arg interface{}) Value {
- return BgBrown(arg)
-}
-
-func (aurora) BgBlue(arg interface{}) Value {
- return BgBlue(arg)
-}
-
-func (aurora) BgMagenta(arg interface{}) Value {
- return BgMagenta(arg)
-}
-
-func (aurora) BgCyan(arg interface{}) Value {
- return BgCyan(arg)
-}
-
-func (aurora) BgWhite(arg interface{}) Value {
- return BgWhite(arg)
-}
-
-func (aurora) BgBrightBlack(arg interface{}) Value {
- return BgBrightBlack(arg)
-}
-
-func (aurora) BgBrightRed(arg interface{}) Value {
- return BgBrightRed(arg)
-}
-
-func (aurora) BgBrightGreen(arg interface{}) Value {
- return BgBrightGreen(arg)
-}
-
-func (aurora) BgBrightYellow(arg interface{}) Value {
- return BgBrightYellow(arg)
-}
-
-func (aurora) BgBrightBlue(arg interface{}) Value {
- return BgBrightBlue(arg)
-}
-
-func (aurora) BgBrightMagenta(arg interface{}) Value {
- return BgBrightMagenta(arg)
-}
-
-func (aurora) BgBrightCyan(arg interface{}) Value {
- return BgBrightCyan(arg)
-}
-
-func (aurora) BgBrightWhite(arg interface{}) Value {
- return BgBrightWhite(arg)
-}
-
-func (aurora) BgIndex(n uint8, arg interface{}) Value {
- return BgIndex(n, arg)
-}
-
-func (aurora) BgGray(n uint8, arg interface{}) Value {
- return BgGray(n, arg)
-}
-
-func (aurora) Colorize(arg interface{}, color Color) Value {
- return Colorize(arg, color)
-}
-
-func (aurora) Sprintf(format interface{}, args ...interface{}) string {
- return Sprintf(format, args...)
-}
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_black_standard.png b/vendor/github.com/logrusorgru/aurora/aurora_black_standard.png
deleted file mode 100644
index 83658d60..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_black_standard.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_colors_black.png b/vendor/github.com/logrusorgru/aurora/aurora_colors_black.png
deleted file mode 100644
index 61b1602a..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_colors_black.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_colors_white.png b/vendor/github.com/logrusorgru/aurora/aurora_colors_white.png
deleted file mode 100644
index ec42b072..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_colors_white.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_formats.gif b/vendor/github.com/logrusorgru/aurora/aurora_formats.gif
deleted file mode 100644
index 670dd1c3..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_formats.gif and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_grayscale.png b/vendor/github.com/logrusorgru/aurora/aurora_grayscale.png
deleted file mode 100644
index 40ecac6a..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_grayscale.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_rarely_supported.png b/vendor/github.com/logrusorgru/aurora/aurora_rarely_supported.png
deleted file mode 100644
index 51b7b6d2..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_rarely_supported.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/aurora_white_standard.png b/vendor/github.com/logrusorgru/aurora/aurora_white_standard.png
deleted file mode 100644
index 1fe99d78..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/aurora_white_standard.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/color.go b/vendor/github.com/logrusorgru/aurora/color.go
deleted file mode 100644
index 486fb674..00000000
--- a/vendor/github.com/logrusorgru/aurora/color.go
+++ /dev/null
@@ -1,398 +0,0 @@
-//
-// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
-// This program is free software. It comes without any warranty,
-// to the extent permitted by applicable law. You can redistribute
-// it and/or modify it under the terms of the Unlicense. See LICENSE
-// file for more details or see below.
-//
-
-//
-// This is free and unencumbered software released into the public domain.
-//
-// Anyone is free to copy, modify, publish, use, compile, sell, or
-// distribute this software, either in source code form or as a compiled
-// binary, for any purpose, commercial or non-commercial, and by any
-// means.
-//
-// In jurisdictions that recognize copyright laws, the author or authors
-// of this software dedicate any and all copyright interest in the
-// software to the public domain. We make this dedication for the benefit
-// of the public at large and to the detriment of our heirs and
-// successors. We intend this dedication to be an overt act of
-// relinquishment in perpetuity of all present and future rights to this
-// software under copyright law.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// For more information, please refer to
-//
-
-package aurora
-
-// A Color type is a color. It can contain
-// one background color, one foreground color
-// and a format, including ideogram related
-// formats.
-type Color uint
-
-/*
-
- Developer note.
-
- The int type is architecture depended and can be
- represented as int32 or int64.
-
- Thus, we can use 32-bits only to be fast and
- cross-platform.
-
- All supported formats requires 14 bits. It is
- first 14 bits.
-
- A foreground color requires 8 bit + 1 bit (presence flag).
- And the same for background color.
-
- The Color representations
-
- [ bg 8 bit ] [fg 8 bit ] [ fg/bg 2 bits ] [ fm 14 bits ]
-
- https://play.golang.org/p/fq2zcNstFoF
-
-*/
-
-// Special formats
-const (
- BoldFm Color = 1 << iota // 1
- FaintFm // 2
- ItalicFm // 3
- UnderlineFm // 4
- SlowBlinkFm // 5
- RapidBlinkFm // 6
- ReverseFm // 7
- ConcealFm // 8
- CrossedOutFm // 9
-
- FrakturFm // 20
- DoublyUnderlineFm // 21 or bold off for some systems
-
- FramedFm // 51
- EncircledFm // 52
- OverlinedFm // 53
-
- InverseFm = ReverseFm // alias to ReverseFm
- BlinkFm = SlowBlinkFm // alias to SlowBlinkFm
- HiddenFm = ConcealFm // alias to ConcealFm
- StrikeThroughFm = CrossedOutFm // alias to CrossedOutFm
-
- maskFm = BoldFm | FaintFm |
- ItalicFm | UnderlineFm |
- SlowBlinkFm | RapidBlinkFm |
- ReverseFm |
- ConcealFm | CrossedOutFm |
-
- FrakturFm | DoublyUnderlineFm |
-
- FramedFm | EncircledFm | OverlinedFm
-
- flagFg Color = 1 << 14 // presence flag (14th bit)
- flagBg Color = 1 << 15 // presence flag (15th bit)
-
- shiftFg = 16 // shift for foreground (starting from 16th bit)
- shiftBg = 24 // shift for background (starting from 24th bit)
-)
-
-// Foreground colors and related formats
-const (
-
- // 8 bits
-
- // [ 0; 7] - 30-37
- // [ 8; 15] - 90-97
- // [ 16; 231] - RGB
- // [232; 255] - grayscale
-
- BlackFg Color = (iota << shiftFg) | flagFg // 30, 90
- RedFg // 31, 91
- GreenFg // 32, 92
- YellowFg // 33, 93
- BlueFg // 34, 94
- MagentaFg // 35, 95
- CyanFg // 36, 96
- WhiteFg // 37, 97
-
- BrightFg Color = ((1 << 3) << shiftFg) | flagFg // -> 90
-
- // the BrightFg itself doesn't represent
- // a color, thus it has not flagFg
-
- // 5 bits
-
- // BrownFg represents brown foreground color.
- //
- // Deprecated: use YellowFg instead, following specifications
- BrownFg = YellowFg
-
- //
- maskFg = (0xff << shiftFg) | flagFg
-)
-
-// Background colors and related formats
-const (
-
- // 8 bits
-
- // [ 0; 7] - 40-47
- // [ 8; 15] - 100-107
- // [ 16; 231] - RGB
- // [232; 255] - grayscale
-
- BlackBg Color = (iota << shiftBg) | flagBg // 40, 100
- RedBg // 41, 101
- GreenBg // 42, 102
- YellowBg // 43, 103
- BlueBg // 44, 104
- MagentaBg // 45, 105
- CyanBg // 46, 106
- WhiteBg // 47, 107
-
- BrightBg Color = ((1 << 3) << shiftBg) | flagBg // -> 100
-
- // the BrightBg itself doesn't represent
- // a color, thus it has not flagBg
-
- // 5 bits
-
- // BrownBg represents brown foreground color.
- //
- // Deprecated: use YellowBg instead, following specifications
- BrownBg = YellowBg
-
- //
- maskBg = (0xff << shiftBg) | flagBg
-)
-
-const (
- availFlags = "-+# 0"
- esc = "\033["
- clear = esc + "0m"
-)
-
-// IsValid returns true always
-//
-// Deprecated: don't use this method anymore
-func (c Color) IsValid() bool {
- return true
-}
-
-// Nos returns string like 1;7;31;45. It
-// may be an empty string for empty color.
-// If the zero is true, then the string
-// is prepended with 0;
-func (c Color) Nos(zero bool) string {
- return string(c.appendNos(make([]byte, 0, 59), zero))
-}
-
-func appendCond(bs []byte, cond, semi bool, vals ...byte) []byte {
- if !cond {
- return bs
- }
- return appendSemi(bs, semi, vals...)
-}
-
-// if the semi is true, then prepend with semicolon
-func appendSemi(bs []byte, semi bool, vals ...byte) []byte {
- if semi {
- bs = append(bs, ';')
- }
- return append(bs, vals...)
-}
-
-func itoa(t byte) string {
- var (
- a [3]byte
- j = 2
- )
- for i := 0; i < 3; i, j = i+1, j-1 {
- a[j] = '0' + t%10
- if t = t / 10; t == 0 {
- break
- }
- }
- return string(a[j:])
-}
-
-func (c Color) appendFg(bs []byte, zero bool) []byte {
-
- if zero || c&maskFm != 0 {
- bs = append(bs, ';')
- }
-
- // 0- 7 : 30-37
- // 8-15 : 90-97
- // > 15 : 38;5;val
-
- switch fg := (c & maskFg) >> shiftFg; {
- case fg <= 7:
- // '3' and the value itself
- bs = append(bs, '3', '0'+byte(fg))
- case fg <= 15:
- // '9' and the value itself
- bs = append(bs, '9', '0'+byte(fg&^0x08)) // clear bright flag
- default:
- bs = append(bs, '3', '8', ';', '5', ';')
- bs = append(bs, itoa(byte(fg))...)
- }
- return bs
-}
-
-func (c Color) appendBg(bs []byte, zero bool) []byte {
-
- if zero || c&(maskFm|maskFg) != 0 {
- bs = append(bs, ';')
- }
-
- // 0- 7 : 40- 47
- // 8-15 : 100-107
- // > 15 : 48;5;val
-
- switch fg := (c & maskBg) >> shiftBg; {
- case fg <= 7:
- // '3' and the value itself
- bs = append(bs, '4', '0'+byte(fg))
- case fg <= 15:
- // '1', '0' and the value itself
- bs = append(bs, '1', '0', '0'+byte(fg&^0x08)) // clear bright flag
- default:
- bs = append(bs, '4', '8', ';', '5', ';')
- bs = append(bs, itoa(byte(fg))...)
- }
- return bs
-}
-
-func (c Color) appendFm9(bs []byte, zero bool) []byte {
-
- bs = appendCond(bs, c&ItalicFm != 0,
- zero || c&(BoldFm|FaintFm) != 0,
- '3')
- bs = appendCond(bs, c&UnderlineFm != 0,
- zero || c&(BoldFm|FaintFm|ItalicFm) != 0,
- '4')
- // don't combine slow and rapid blink using only
- // on of them, preferring slow blink
- if c&SlowBlinkFm != 0 {
- bs = appendSemi(bs,
- zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
- '5')
- } else if c&RapidBlinkFm != 0 {
- bs = appendSemi(bs,
- zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
- '6')
- }
-
- // including 1-2
- const mask6i = BoldFm | FaintFm |
- ItalicFm | UnderlineFm |
- SlowBlinkFm | RapidBlinkFm
-
- bs = appendCond(bs, c&ReverseFm != 0,
- zero || c&(mask6i) != 0,
- '7')
- bs = appendCond(bs, c&ConcealFm != 0,
- zero || c&(mask6i|ReverseFm) != 0,
- '8')
- bs = appendCond(bs, c&CrossedOutFm != 0,
- zero || c&(mask6i|ReverseFm|ConcealFm) != 0,
- '9')
-
- return bs
-}
-
-// append 1;3;38;5;216 like string that represents ANSI
-// color of the Color; the zero argument requires
-// appending of '0' before to reset previous format
-// and colors
-func (c Color) appendNos(bs []byte, zero bool) []byte {
-
- if zero {
- bs = append(bs, '0') // reset previous
- }
-
- // formats
- //
-
- if c&maskFm != 0 {
-
- // 1-2
-
- // don't combine bold and faint using only on of them, preferring bold
-
- if c&BoldFm != 0 {
- bs = appendSemi(bs, zero, '1')
- } else if c&FaintFm != 0 {
- bs = appendSemi(bs, zero, '2')
- }
-
- // 3-9
-
- const mask9 = ItalicFm | UnderlineFm |
- SlowBlinkFm | RapidBlinkFm |
- ReverseFm | ConcealFm | CrossedOutFm
-
- if c&mask9 != 0 {
- bs = c.appendFm9(bs, zero)
- }
-
- // 20-21
-
- const (
- mask21 = FrakturFm | DoublyUnderlineFm
- mask9i = BoldFm | FaintFm | mask9
- )
-
- if c&mask21 != 0 {
- bs = appendCond(bs, c&FrakturFm != 0,
- zero || c&mask9i != 0,
- '2', '0')
- bs = appendCond(bs, c&DoublyUnderlineFm != 0,
- zero || c&(mask9i|FrakturFm) != 0,
- '2', '1')
- }
-
- // 50-53
-
- const (
- mask53 = FramedFm | EncircledFm | OverlinedFm
- mask21i = mask9i | mask21
- )
-
- if c&mask53 != 0 {
- bs = appendCond(bs, c&FramedFm != 0,
- zero || c&mask21i != 0,
- '5', '1')
- bs = appendCond(bs, c&EncircledFm != 0,
- zero || c&(mask21i|FramedFm) != 0,
- '5', '2')
- bs = appendCond(bs, c&OverlinedFm != 0,
- zero || c&(mask21i|FramedFm|EncircledFm) != 0,
- '5', '3')
- }
-
- }
-
- // foreground
- if c&maskFg != 0 {
- bs = c.appendFg(bs, zero)
- }
-
- // background
- if c&maskBg != 0 {
- bs = c.appendBg(bs, zero)
- }
-
- return bs
-}
diff --git a/vendor/github.com/logrusorgru/aurora/disable.png b/vendor/github.com/logrusorgru/aurora/disable.png
deleted file mode 100644
index 0dd1d63f..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/disable.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/enable.png b/vendor/github.com/logrusorgru/aurora/enable.png
deleted file mode 100644
index a488367c..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/enable.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/gopher_aurora.png b/vendor/github.com/logrusorgru/aurora/gopher_aurora.png
deleted file mode 100644
index 8f61bb20..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/gopher_aurora.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/printf.png b/vendor/github.com/logrusorgru/aurora/printf.png
deleted file mode 100644
index 5978844a..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/printf.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/simple.png b/vendor/github.com/logrusorgru/aurora/simple.png
deleted file mode 100644
index 50edf042..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/simple.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/sprintf.go b/vendor/github.com/logrusorgru/aurora/sprintf.go
deleted file mode 100644
index b92d5933..00000000
--- a/vendor/github.com/logrusorgru/aurora/sprintf.go
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
-// This program is free software. It comes without any warranty,
-// to the extent permitted by applicable law. You can redistribute
-// it and/or modify it under the terms of the Unlicense. See LICENSE
-// file for more details or see below.
-//
-
-//
-// This is free and unencumbered software released into the public domain.
-//
-// Anyone is free to copy, modify, publish, use, compile, sell, or
-// distribute this software, either in source code form or as a compiled
-// binary, for any purpose, commercial or non-commercial, and by any
-// means.
-//
-// In jurisdictions that recognize copyright laws, the author or authors
-// of this software dedicate any and all copyright interest in the
-// software to the public domain. We make this dedication for the benefit
-// of the public at large and to the detriment of our heirs and
-// successors. We intend this dedication to be an overt act of
-// relinquishment in perpetuity of all present and future rights to this
-// software under copyright law.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// For more information, please refer to
-//
-
-package aurora
-
-import (
- "fmt"
-)
-
-// Sprintf allows to use Value as format. For example
-//
-// v := Sprintf(Red("total: +3.5f points"), Blue(3.14))
-//
-// In this case "total:" and "points" will be red, but
-// 3.14 will be blue. But, in another example
-//
-// v := Sprintf(Red("total: +3.5f points"), 3.14)
-//
-// full string will be red. And no way to clear 3.14 to
-// default format and color
-func Sprintf(format interface{}, args ...interface{}) string {
- switch ft := format.(type) {
- case string:
- return fmt.Sprintf(ft, args...)
- case Value:
- for i, v := range args {
- if val, ok := v.(Value); ok {
- args[i] = val.setTail(ft.Color())
- continue
- }
- }
- return fmt.Sprintf(ft.String(), args...)
- }
- // unknown type of format (we hope it's a string)
- return fmt.Sprintf(fmt.Sprint(format), args...)
-}
diff --git a/vendor/github.com/logrusorgru/aurora/sprintf.png b/vendor/github.com/logrusorgru/aurora/sprintf.png
deleted file mode 100644
index df2b2cc0..00000000
Binary files a/vendor/github.com/logrusorgru/aurora/sprintf.png and /dev/null differ
diff --git a/vendor/github.com/logrusorgru/aurora/value.go b/vendor/github.com/logrusorgru/aurora/value.go
deleted file mode 100644
index feda25af..00000000
--- a/vendor/github.com/logrusorgru/aurora/value.go
+++ /dev/null
@@ -1,745 +0,0 @@
-//
-// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
-// This program is free software. It comes without any warranty,
-// to the extent permitted by applicable law. You can redistribute
-// it and/or modify it under the terms of the Unlicense. See LICENSE
-// file for more details or see below.
-//
-
-//
-// This is free and unencumbered software released into the public domain.
-//
-// Anyone is free to copy, modify, publish, use, compile, sell, or
-// distribute this software, either in source code form or as a compiled
-// binary, for any purpose, commercial or non-commercial, and by any
-// means.
-//
-// In jurisdictions that recognize copyright laws, the author or authors
-// of this software dedicate any and all copyright interest in the
-// software to the public domain. We make this dedication for the benefit
-// of the public at large and to the detriment of our heirs and
-// successors. We intend this dedication to be an overt act of
-// relinquishment in perpetuity of all present and future rights to this
-// software under copyright law.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// For more information, please refer to
-//
-
-package aurora
-
-import (
- "fmt"
- "strconv"
- "unicode/utf8"
-)
-
-// A Value represents any printable value
-// with it's color
-type Value interface {
- // String returns string with colors. If there are any color
- // or format the string will be terminated with \033[0m
- fmt.Stringer
- // Format implements fmt.Formatter interface
- fmt.Formatter
- // Color returns value's color
- Color() Color
- // Value returns value's value (welcome to the tautology club)
- Value() interface{}
-
- // internals
- tail() Color
- setTail(Color) Value
-
- // Bleach returns copy of original value without colors
- //
- // Deprecated: use Reset instead.
- Bleach() Value
- // Reset colors and formats
- Reset() Value
-
- //
- // Formats
- //
- //
- // Bold or increased intensity (1).
- Bold() Value
- // Faint, decreased intensity, reset the Bold (2).
- Faint() Value
- //
- // DoublyUnderline or Bold off, double-underline
- // per ECMA-48 (21). It depends.
- DoublyUnderline() Value
- // Fraktur, rarely supported (20).
- Fraktur() Value
- //
- // Italic, not widely supported, sometimes
- // treated as inverse (3).
- Italic() Value
- // Underline (4).
- Underline() Value
- //
- // SlowBlink, blinking less than 150
- // per minute (5).
- SlowBlink() Value
- // RapidBlink, blinking 150+ per minute,
- // not widely supported (6).
- RapidBlink() Value
- // Blink is alias for the SlowBlink.
- Blink() Value
- //
- // Reverse video, swap foreground and
- // background colors (7).
- Reverse() Value
- // Inverse is alias for the Reverse
- Inverse() Value
- //
- // Conceal, hidden, not widely supported (8).
- Conceal() Value
- // Hidden is alias for the Conceal
- Hidden() Value
- //
- // CrossedOut, characters legible, but
- // marked for deletion (9).
- CrossedOut() Value
- // StrikeThrough is alias for the CrossedOut.
- StrikeThrough() Value
- //
- // Framed (51).
- Framed() Value
- // Encircled (52).
- Encircled() Value
- //
- // Overlined (53).
- Overlined() Value
-
- //
- // Foreground colors
- //
- //
- // Black foreground color (30)
- Black() Value
- // Red foreground color (31)
- Red() Value
- // Green foreground color (32)
- Green() Value
- // Yellow foreground color (33)
- Yellow() Value
- // Brown foreground color (33)
- //
- // Deprecated: use Yellow instead, following specification
- Brown() Value
- // Blue foreground color (34)
- Blue() Value
- // Magenta foreground color (35)
- Magenta() Value
- // Cyan foreground color (36)
- Cyan() Value
- // White foreground color (37)
- White() Value
- //
- // Bright foreground colors
- //
- // BrightBlack foreground color (90)
- BrightBlack() Value
- // BrightRed foreground color (91)
- BrightRed() Value
- // BrightGreen foreground color (92)
- BrightGreen() Value
- // BrightYellow foreground color (93)
- BrightYellow() Value
- // BrightBlue foreground color (94)
- BrightBlue() Value
- // BrightMagenta foreground color (95)
- BrightMagenta() Value
- // BrightCyan foreground color (96)
- BrightCyan() Value
- // BrightWhite foreground color (97)
- BrightWhite() Value
- //
- // Other
- //
- // Index of pre-defined 8-bit foreground color
- // from 0 to 255 (38;5;n).
- //
- // 0- 7: standard colors (as in ESC [ 30–37 m)
- // 8- 15: high intensity colors (as in ESC [ 90–97 m)
- // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
- // 232-255: grayscale from black to white in 24 steps
- //
- Index(n uint8) Value
- // Gray from 0 to 24.
- Gray(n uint8) Value
-
- //
- // Background colors
- //
- //
- // BgBlack background color (40)
- BgBlack() Value
- // BgRed background color (41)
- BgRed() Value
- // BgGreen background color (42)
- BgGreen() Value
- // BgYellow background color (43)
- BgYellow() Value
- // BgBrown background color (43)
- //
- // Deprecated: use BgYellow instead, following specification
- BgBrown() Value
- // BgBlue background color (44)
- BgBlue() Value
- // BgMagenta background color (45)
- BgMagenta() Value
- // BgCyan background color (46)
- BgCyan() Value
- // BgWhite background color (47)
- BgWhite() Value
- //
- // Bright background colors
- //
- // BgBrightBlack background color (100)
- BgBrightBlack() Value
- // BgBrightRed background color (101)
- BgBrightRed() Value
- // BgBrightGreen background color (102)
- BgBrightGreen() Value
- // BgBrightYellow background color (103)
- BgBrightYellow() Value
- // BgBrightBlue background color (104)
- BgBrightBlue() Value
- // BgBrightMagenta background color (105)
- BgBrightMagenta() Value
- // BgBrightCyan background color (106)
- BgBrightCyan() Value
- // BgBrightWhite background color (107)
- BgBrightWhite() Value
- //
- // Other
- //
- // BgIndex of 8-bit pre-defined background color
- // from 0 to 255 (48;5;n).
- //
- // 0- 7: standard colors (as in ESC [ 40–47 m)
- // 8- 15: high intensity colors (as in ESC [100–107 m)
- // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
- // 232-255: grayscale from black to white in 24 steps
- //
- BgIndex(n uint8) Value
- // BgGray from 0 to 24.
- BgGray(n uint8) Value
-
- //
- // Special
- //
- // Colorize removes existing colors and
- // formats of the argument and applies given.
- Colorize(color Color) Value
-}
-
-// Value without colors
-
-type valueClear struct {
- value interface{}
-}
-
-func (vc valueClear) String() string { return fmt.Sprint(vc.value) }
-
-func (vc valueClear) Color() Color { return 0 }
-func (vc valueClear) Value() interface{} { return vc.value }
-
-func (vc valueClear) tail() Color { return 0 }
-func (vc valueClear) setTail(Color) Value { return vc }
-
-func (vc valueClear) Bleach() Value { return vc }
-func (vc valueClear) Reset() Value { return vc }
-
-func (vc valueClear) Bold() Value { return vc }
-func (vc valueClear) Faint() Value { return vc }
-func (vc valueClear) DoublyUnderline() Value { return vc }
-func (vc valueClear) Fraktur() Value { return vc }
-func (vc valueClear) Italic() Value { return vc }
-func (vc valueClear) Underline() Value { return vc }
-func (vc valueClear) SlowBlink() Value { return vc }
-func (vc valueClear) RapidBlink() Value { return vc }
-func (vc valueClear) Blink() Value { return vc }
-func (vc valueClear) Reverse() Value { return vc }
-func (vc valueClear) Inverse() Value { return vc }
-func (vc valueClear) Conceal() Value { return vc }
-func (vc valueClear) Hidden() Value { return vc }
-func (vc valueClear) CrossedOut() Value { return vc }
-func (vc valueClear) StrikeThrough() Value { return vc }
-func (vc valueClear) Framed() Value { return vc }
-func (vc valueClear) Encircled() Value { return vc }
-func (vc valueClear) Overlined() Value { return vc }
-
-func (vc valueClear) Black() Value { return vc }
-func (vc valueClear) Red() Value { return vc }
-func (vc valueClear) Green() Value { return vc }
-func (vc valueClear) Yellow() Value { return vc }
-func (vc valueClear) Brown() Value { return vc }
-func (vc valueClear) Blue() Value { return vc }
-func (vc valueClear) Magenta() Value { return vc }
-func (vc valueClear) Cyan() Value { return vc }
-func (vc valueClear) White() Value { return vc }
-func (vc valueClear) BrightBlack() Value { return vc }
-func (vc valueClear) BrightRed() Value { return vc }
-func (vc valueClear) BrightGreen() Value { return vc }
-func (vc valueClear) BrightYellow() Value { return vc }
-func (vc valueClear) BrightBlue() Value { return vc }
-func (vc valueClear) BrightMagenta() Value { return vc }
-func (vc valueClear) BrightCyan() Value { return vc }
-func (vc valueClear) BrightWhite() Value { return vc }
-func (vc valueClear) Index(uint8) Value { return vc }
-func (vc valueClear) Gray(uint8) Value { return vc }
-
-func (vc valueClear) BgBlack() Value { return vc }
-func (vc valueClear) BgRed() Value { return vc }
-func (vc valueClear) BgGreen() Value { return vc }
-func (vc valueClear) BgYellow() Value { return vc }
-func (vc valueClear) BgBrown() Value { return vc }
-func (vc valueClear) BgBlue() Value { return vc }
-func (vc valueClear) BgMagenta() Value { return vc }
-func (vc valueClear) BgCyan() Value { return vc }
-func (vc valueClear) BgWhite() Value { return vc }
-func (vc valueClear) BgBrightBlack() Value { return vc }
-func (vc valueClear) BgBrightRed() Value { return vc }
-func (vc valueClear) BgBrightGreen() Value { return vc }
-func (vc valueClear) BgBrightYellow() Value { return vc }
-func (vc valueClear) BgBrightBlue() Value { return vc }
-func (vc valueClear) BgBrightMagenta() Value { return vc }
-func (vc valueClear) BgBrightCyan() Value { return vc }
-func (vc valueClear) BgBrightWhite() Value { return vc }
-func (vc valueClear) BgIndex(uint8) Value { return vc }
-func (vc valueClear) BgGray(uint8) Value { return vc }
-func (vc valueClear) Colorize(Color) Value { return vc }
-
-func (vc valueClear) Format(s fmt.State, verb rune) {
- // it's enough for many cases (%-+020.10f)
- // % - 1
- // availFlags - 3 (5)
- // width - 2
- // prec - 3 (.23)
- // verb - 1
- // --------------
- // 10
- format := make([]byte, 1, 10)
- format[0] = '%'
- var f byte
- for i := 0; i < len(availFlags); i++ {
- if f = availFlags[i]; s.Flag(int(f)) {
- format = append(format, f)
- }
- }
- var width, prec int
- var ok bool
- if width, ok = s.Width(); ok {
- format = strconv.AppendInt(format, int64(width), 10)
- }
- if prec, ok = s.Precision(); ok {
- format = append(format, '.')
- format = strconv.AppendInt(format, int64(prec), 10)
- }
- if verb > utf8.RuneSelf {
- format = append(format, string(verb)...)
- } else {
- format = append(format, byte(verb))
- }
- fmt.Fprintf(s, string(format), vc.value)
-}
-
-// Value within colors
-
-type value struct {
- value interface{} // value as it
- color Color // this color
- tailColor Color // tail color
-}
-
-func (v value) String() string {
- if v.color != 0 {
- if v.tailColor != 0 {
- return esc + v.color.Nos(true) + "m" +
- fmt.Sprint(v.value) +
- esc + v.tailColor.Nos(true) + "m"
- }
- return esc + v.color.Nos(false) + "m" + fmt.Sprint(v.value) + clear
- }
- return fmt.Sprint(v.value)
-}
-
-func (v value) Color() Color { return v.color }
-
-func (v value) Bleach() Value {
- v.color, v.tailColor = 0, 0
- return v
-}
-
-func (v value) Reset() Value {
- v.color, v.tailColor = 0, 0
- return v
-}
-
-func (v value) tail() Color { return v.tailColor }
-
-func (v value) setTail(t Color) Value {
- v.tailColor = t
- return v
-}
-
-func (v value) Value() interface{} { return v.value }
-
-func (v value) Format(s fmt.State, verb rune) {
-
- // it's enough for many cases (%-+020.10f)
- // % - 1
- // availFlags - 3 (5)
- // width - 2
- // prec - 3 (.23)
- // verb - 1
- // --------------
- // 10
- // +
- // \033[ 5
- // 0;1;3;4;5;7;8;9;20;21;51;52;53 30
- // 38;5;216 8
- // 48;5;216 8
- // m 1
- // +
- // \033[0m 7
- //
- // x2 (possible tail color)
- //
- // 10 + 59 * 2 = 128
-
- format := make([]byte, 0, 128)
- if v.color != 0 {
- format = append(format, esc...)
- format = v.color.appendNos(format, v.tailColor != 0)
- format = append(format, 'm')
- }
- format = append(format, '%')
- var f byte
- for i := 0; i < len(availFlags); i++ {
- if f = availFlags[i]; s.Flag(int(f)) {
- format = append(format, f)
- }
- }
- var width, prec int
- var ok bool
- if width, ok = s.Width(); ok {
- format = strconv.AppendInt(format, int64(width), 10)
- }
- if prec, ok = s.Precision(); ok {
- format = append(format, '.')
- format = strconv.AppendInt(format, int64(prec), 10)
- }
- if verb > utf8.RuneSelf {
- format = append(format, string(verb)...)
- } else {
- format = append(format, byte(verb))
- }
- if v.color != 0 {
- if v.tailColor != 0 {
- // set next (previous) format clearing current one
- format = append(format, esc...)
- format = v.tailColor.appendNos(format, true)
- format = append(format, 'm')
- } else {
- format = append(format, clear...) // just clear
- }
- }
- fmt.Fprintf(s, string(format), v.value)
-}
-
-func (v value) Bold() Value {
- v.color = (v.color &^ FaintFm) | BoldFm
- return v
-}
-
-func (v value) Faint() Value {
- v.color = (v.color &^ BoldFm) | FaintFm
- return v
-}
-
-func (v value) DoublyUnderline() Value {
- v.color |= DoublyUnderlineFm
- return v
-}
-
-func (v value) Fraktur() Value {
- v.color |= FrakturFm
- return v
-}
-
-func (v value) Italic() Value {
- v.color |= ItalicFm
- return v
-}
-
-func (v value) Underline() Value {
- v.color |= UnderlineFm
- return v
-}
-
-func (v value) SlowBlink() Value {
- v.color = (v.color &^ RapidBlinkFm) | SlowBlinkFm
- return v
-}
-
-func (v value) RapidBlink() Value {
- v.color = (v.color &^ SlowBlinkFm) | RapidBlinkFm
- return v
-}
-
-func (v value) Blink() Value {
- return v.SlowBlink()
-}
-
-func (v value) Reverse() Value {
- v.color |= ReverseFm
- return v
-}
-
-func (v value) Inverse() Value {
- return v.Reverse()
-}
-
-func (v value) Conceal() Value {
- v.color |= ConcealFm
- return v
-}
-
-func (v value) Hidden() Value {
- return v.Conceal()
-}
-
-func (v value) CrossedOut() Value {
- v.color |= CrossedOutFm
- return v
-}
-
-func (v value) StrikeThrough() Value {
- return v.CrossedOut()
-}
-
-func (v value) Framed() Value {
- v.color |= FramedFm
- return v
-}
-
-func (v value) Encircled() Value {
- v.color |= EncircledFm
- return v
-}
-
-func (v value) Overlined() Value {
- v.color |= OverlinedFm
- return v
-}
-
-func (v value) Black() Value {
- v.color = (v.color &^ maskFg) | BlackFg
- return v
-}
-
-func (v value) Red() Value {
- v.color = (v.color &^ maskFg) | RedFg
- return v
-}
-
-func (v value) Green() Value {
- v.color = (v.color &^ maskFg) | GreenFg
- return v
-}
-
-func (v value) Yellow() Value {
- v.color = (v.color &^ maskFg) | YellowFg
- return v
-}
-
-func (v value) Brown() Value {
- return v.Yellow()
-}
-
-func (v value) Blue() Value {
- v.color = (v.color &^ maskFg) | BlueFg
- return v
-}
-
-func (v value) Magenta() Value {
- v.color = (v.color &^ maskFg) | MagentaFg
- return v
-}
-
-func (v value) Cyan() Value {
- v.color = (v.color &^ maskFg) | CyanFg
- return v
-}
-
-func (v value) White() Value {
- v.color = (v.color &^ maskFg) | WhiteFg
- return v
-}
-
-func (v value) BrightBlack() Value {
- v.color = (v.color &^ maskFg) | BrightFg | BlackFg
- return v
-}
-
-func (v value) BrightRed() Value {
- v.color = (v.color &^ maskFg) | BrightFg | RedFg
- return v
-}
-
-func (v value) BrightGreen() Value {
- v.color = (v.color &^ maskFg) | BrightFg | GreenFg
- return v
-}
-
-func (v value) BrightYellow() Value {
- v.color = (v.color &^ maskFg) | BrightFg | YellowFg
- return v
-}
-
-func (v value) BrightBlue() Value {
- v.color = (v.color &^ maskFg) | BrightFg | BlueFg
- return v
-}
-
-func (v value) BrightMagenta() Value {
- v.color = (v.color &^ maskFg) | BrightFg | MagentaFg
- return v
-}
-
-func (v value) BrightCyan() Value {
- v.color = (v.color &^ maskFg) | BrightFg | CyanFg
- return v
-}
-
-func (v value) BrightWhite() Value {
- v.color = (v.color &^ maskFg) | BrightFg | WhiteFg
- return v
-}
-
-func (v value) Index(n uint8) Value {
- v.color = (v.color &^ maskFg) | (Color(n) << shiftFg) | flagFg
- return v
-}
-
-func (v value) Gray(n uint8) Value {
- if n > 23 {
- n = 23
- }
- v.color = (v.color &^ maskFg) | (Color(232+n) << shiftFg) | flagFg
- return v
-}
-
-func (v value) BgBlack() Value {
- v.color = (v.color &^ maskBg) | BlackBg
- return v
-}
-
-func (v value) BgRed() Value {
- v.color = (v.color &^ maskBg) | RedBg
- return v
-}
-
-func (v value) BgGreen() Value {
- v.color = (v.color &^ maskBg) | GreenBg
- return v
-}
-
-func (v value) BgYellow() Value {
- v.color = (v.color &^ maskBg) | YellowBg
- return v
-}
-
-func (v value) BgBrown() Value {
- return v.BgYellow()
-}
-
-func (v value) BgBlue() Value {
- v.color = (v.color &^ maskBg) | BlueBg
- return v
-}
-
-func (v value) BgMagenta() Value {
- v.color = (v.color &^ maskBg) | MagentaBg
- return v
-}
-
-func (v value) BgCyan() Value {
- v.color = (v.color &^ maskBg) | CyanBg
- return v
-}
-
-func (v value) BgWhite() Value {
- v.color = (v.color &^ maskBg) | WhiteBg
- return v
-}
-
-func (v value) BgBrightBlack() Value {
- v.color = (v.color &^ maskBg) | BrightBg | BlackBg
- return v
-}
-
-func (v value) BgBrightRed() Value {
- v.color = (v.color &^ maskBg) | BrightBg | RedBg
- return v
-}
-
-func (v value) BgBrightGreen() Value {
- v.color = (v.color &^ maskBg) | BrightBg | GreenBg
- return v
-}
-
-func (v value) BgBrightYellow() Value {
- v.color = (v.color &^ maskBg) | BrightBg | YellowBg
- return v
-}
-
-func (v value) BgBrightBlue() Value {
- v.color = (v.color &^ maskBg) | BrightBg | BlueBg
- return v
-}
-
-func (v value) BgBrightMagenta() Value {
- v.color = (v.color &^ maskBg) | BrightBg | MagentaBg
- return v
-}
-
-func (v value) BgBrightCyan() Value {
- v.color = (v.color &^ maskBg) | BrightBg | CyanBg
- return v
-}
-
-func (v value) BgBrightWhite() Value {
- v.color = (v.color &^ maskBg) | BrightBg | WhiteBg
- return v
-}
-
-func (v value) BgIndex(n uint8) Value {
- v.color = (v.color &^ maskBg) | (Color(n) << shiftBg) | flagBg
- return v
-}
-
-func (v value) BgGray(n uint8) Value {
- if n > 23 {
- n = 23
- }
- v.color = (v.color &^ maskBg) | (Color(232+n) << shiftBg) | flagBg
- return v
-}
-
-func (v value) Colorize(color Color) Value {
- v.color = color
- return v
-}
diff --git a/vendor/github.com/logrusorgru/aurora/wrap.go b/vendor/github.com/logrusorgru/aurora/wrap.go
deleted file mode 100644
index 44e1aa6c..00000000
--- a/vendor/github.com/logrusorgru/aurora/wrap.go
+++ /dev/null
@@ -1,558 +0,0 @@
-//
-// Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
-// This program is free software. It comes without any warranty,
-// to the extent permitted by applicable law. You can redistribute
-// it and/or modify it under the terms of the Unlicense. See LICENSE
-// file for more details or see below.
-//
-
-//
-// This is free and unencumbered software released into the public domain.
-//
-// Anyone is free to copy, modify, publish, use, compile, sell, or
-// distribute this software, either in source code form or as a compiled
-// binary, for any purpose, commercial or non-commercial, and by any
-// means.
-//
-// In jurisdictions that recognize copyright laws, the author or authors
-// of this software dedicate any and all copyright interest in the
-// software to the public domain. We make this dedication for the benefit
-// of the public at large and to the detriment of our heirs and
-// successors. We intend this dedication to be an overt act of
-// relinquishment in perpetuity of all present and future rights to this
-// software under copyright law.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-// For more information, please refer to
-//
-
-package aurora
-
-// Colorize wraps given value into Value with
-// given colors. For example
-//
-// s := Colorize("some", BlueFg|GreenBg|BoldFm)
-//
-// returns a Value with blue foreground, green
-// background and bold. Unlike functions like
-// Red/BgBlue/Bold etc. This function clears
-// all previous colors and formats. Thus
-//
-// s := Colorize(Red("some"), BgBlue)
-//
-// clears red color from value
-func Colorize(arg interface{}, color Color) Value {
- if val, ok := arg.(value); ok {
- val.color = color
- return val
- }
- return value{arg, color, 0}
-}
-
-// Reset wraps given argument returning Value
-// without formats and colors.
-func Reset(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Reset()
- }
- return value{value: arg}
-}
-
-//
-// Formats
-//
-
-// Bold or increased intensity (1).
-func Bold(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Bold()
- }
- return value{value: arg, color: BoldFm}
-}
-
-// Faint decreases intensity (2).
-// The Faint rejects the Bold.
-func Faint(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Faint()
- }
- return value{value: arg, color: FaintFm}
-}
-
-// DoublyUnderline or Bold off, double-underline
-// per ECMA-48 (21).
-func DoublyUnderline(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.DoublyUnderline()
- }
- return value{value: arg, color: DoublyUnderlineFm}
-}
-
-// Fraktur is rarely supported (20).
-func Fraktur(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Fraktur()
- }
- return value{value: arg, color: FrakturFm}
-}
-
-// Italic is not widely supported, sometimes
-// treated as inverse (3).
-func Italic(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Italic()
- }
- return value{value: arg, color: ItalicFm}
-}
-
-// Underline (4).
-func Underline(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Underline()
- }
- return value{value: arg, color: UnderlineFm}
-}
-
-// SlowBlink makes text blink less than
-// 150 per minute (5).
-func SlowBlink(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.SlowBlink()
- }
- return value{value: arg, color: SlowBlinkFm}
-}
-
-// RapidBlink makes text blink 150+ per
-// minute. It is not widely supported (6).
-func RapidBlink(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.RapidBlink()
- }
- return value{value: arg, color: RapidBlinkFm}
-}
-
-// Blink is alias for the SlowBlink.
-func Blink(arg interface{}) Value {
- return SlowBlink(arg)
-}
-
-// Reverse video, swap foreground and
-// background colors (7).
-func Reverse(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Reverse()
- }
- return value{value: arg, color: ReverseFm}
-}
-
-// Inverse is alias for the Reverse
-func Inverse(arg interface{}) Value {
- return Reverse(arg)
-}
-
-// Conceal hides text, preserving an ability to select
-// the text and copy it. It is not widely supported (8).
-func Conceal(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Conceal()
- }
- return value{value: arg, color: ConcealFm}
-}
-
-// Hidden is alias for the Conceal
-func Hidden(arg interface{}) Value {
- return Conceal(arg)
-}
-
-// CrossedOut makes characters legible, but
-// marked for deletion (9).
-func CrossedOut(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.CrossedOut()
- }
- return value{value: arg, color: CrossedOutFm}
-}
-
-// StrikeThrough is alias for the CrossedOut.
-func StrikeThrough(arg interface{}) Value {
- return CrossedOut(arg)
-}
-
-// Framed (51).
-func Framed(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Framed()
- }
- return value{value: arg, color: FramedFm}
-}
-
-// Encircled (52).
-func Encircled(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Encircled()
- }
- return value{value: arg, color: EncircledFm}
-}
-
-// Overlined (53).
-func Overlined(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Overlined()
- }
- return value{value: arg, color: OverlinedFm}
-}
-
-//
-// Foreground colors
-//
-//
-
-// Black foreground color (30)
-func Black(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Black()
- }
- return value{value: arg, color: BlackFg}
-}
-
-// Red foreground color (31)
-func Red(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Red()
- }
- return value{value: arg, color: RedFg}
-}
-
-// Green foreground color (32)
-func Green(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Green()
- }
- return value{value: arg, color: GreenFg}
-}
-
-// Yellow foreground color (33)
-func Yellow(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Yellow()
- }
- return value{value: arg, color: YellowFg}
-}
-
-// Brown foreground color (33)
-//
-// Deprecated: use Yellow instead, following specification
-func Brown(arg interface{}) Value {
- return Yellow(arg)
-}
-
-// Blue foreground color (34)
-func Blue(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Blue()
- }
- return value{value: arg, color: BlueFg}
-}
-
-// Magenta foreground color (35)
-func Magenta(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Magenta()
- }
- return value{value: arg, color: MagentaFg}
-}
-
-// Cyan foreground color (36)
-func Cyan(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Cyan()
- }
- return value{value: arg, color: CyanFg}
-}
-
-// White foreground color (37)
-func White(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.White()
- }
- return value{value: arg, color: WhiteFg}
-}
-
-//
-// Bright foreground colors
-//
-
-// BrightBlack foreground color (90)
-func BrightBlack(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightBlack()
- }
- return value{value: arg, color: BrightFg | BlackFg}
-}
-
-// BrightRed foreground color (91)
-func BrightRed(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightRed()
- }
- return value{value: arg, color: BrightFg | RedFg}
-}
-
-// BrightGreen foreground color (92)
-func BrightGreen(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightGreen()
- }
- return value{value: arg, color: BrightFg | GreenFg}
-}
-
-// BrightYellow foreground color (93)
-func BrightYellow(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightYellow()
- }
- return value{value: arg, color: BrightFg | YellowFg}
-}
-
-// BrightBlue foreground color (94)
-func BrightBlue(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightBlue()
- }
- return value{value: arg, color: BrightFg | BlueFg}
-}
-
-// BrightMagenta foreground color (95)
-func BrightMagenta(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightMagenta()
- }
- return value{value: arg, color: BrightFg | MagentaFg}
-}
-
-// BrightCyan foreground color (96)
-func BrightCyan(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightCyan()
- }
- return value{value: arg, color: BrightFg | CyanFg}
-}
-
-// BrightWhite foreground color (97)
-func BrightWhite(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BrightWhite()
- }
- return value{value: arg, color: BrightFg | WhiteFg}
-}
-
-//
-// Other
-//
-
-// Index of pre-defined 8-bit foreground color
-// from 0 to 255 (38;5;n).
-//
-// 0- 7: standard colors (as in ESC [ 30–37 m)
-// 8- 15: high intensity colors (as in ESC [ 90–97 m)
-// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
-// 232-255: grayscale from black to white in 24 steps
-//
-func Index(n uint8, arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Index(n)
- }
- return value{value: arg, color: (Color(n) << shiftFg) | flagFg}
-}
-
-// Gray from 0 to 24.
-func Gray(n uint8, arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.Gray(n)
- }
- if n > 23 {
- n = 23
- }
- return value{value: arg, color: (Color(232+n) << shiftFg) | flagFg}
-}
-
-//
-// Background colors
-//
-//
-
-// BgBlack background color (40)
-func BgBlack(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBlack()
- }
- return value{value: arg, color: BlackBg}
-}
-
-// BgRed background color (41)
-func BgRed(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgRed()
- }
- return value{value: arg, color: RedBg}
-}
-
-// BgGreen background color (42)
-func BgGreen(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgGreen()
- }
- return value{value: arg, color: GreenBg}
-}
-
-// BgYellow background color (43)
-func BgYellow(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgYellow()
- }
- return value{value: arg, color: YellowBg}
-}
-
-// BgBrown background color (43)
-//
-// Deprecated: use BgYellow instead, following specification
-func BgBrown(arg interface{}) Value {
- return BgYellow(arg)
-}
-
-// BgBlue background color (44)
-func BgBlue(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBlue()
- }
- return value{value: arg, color: BlueBg}
-}
-
-// BgMagenta background color (45)
-func BgMagenta(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgMagenta()
- }
- return value{value: arg, color: MagentaBg}
-}
-
-// BgCyan background color (46)
-func BgCyan(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgCyan()
- }
- return value{value: arg, color: CyanBg}
-}
-
-// BgWhite background color (47)
-func BgWhite(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgWhite()
- }
- return value{value: arg, color: WhiteBg}
-}
-
-//
-// Bright background colors
-//
-
-// BgBrightBlack background color (100)
-func BgBrightBlack(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightBlack()
- }
- return value{value: arg, color: BrightBg | BlackBg}
-}
-
-// BgBrightRed background color (101)
-func BgBrightRed(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightRed()
- }
- return value{value: arg, color: BrightBg | RedBg}
-}
-
-// BgBrightGreen background color (102)
-func BgBrightGreen(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightGreen()
- }
- return value{value: arg, color: BrightBg | GreenBg}
-}
-
-// BgBrightYellow background color (103)
-func BgBrightYellow(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightYellow()
- }
- return value{value: arg, color: BrightBg | YellowBg}
-}
-
-// BgBrightBlue background color (104)
-func BgBrightBlue(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightBlue()
- }
- return value{value: arg, color: BrightBg | BlueBg}
-}
-
-// BgBrightMagenta background color (105)
-func BgBrightMagenta(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightMagenta()
- }
- return value{value: arg, color: BrightBg | MagentaBg}
-}
-
-// BgBrightCyan background color (106)
-func BgBrightCyan(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightCyan()
- }
- return value{value: arg, color: BrightBg | CyanBg}
-}
-
-// BgBrightWhite background color (107)
-func BgBrightWhite(arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgBrightWhite()
- }
- return value{value: arg, color: BrightBg | WhiteBg}
-}
-
-//
-// Other
-//
-
-// BgIndex of 8-bit pre-defined background color
-// from 0 to 255 (48;5;n).
-//
-// 0- 7: standard colors (as in ESC [ 40–47 m)
-// 8- 15: high intensity colors (as in ESC [100–107 m)
-// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
-// 232-255: grayscale from black to white in 24 steps
-//
-func BgIndex(n uint8, arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgIndex(n)
- }
- return value{value: arg, color: (Color(n) << shiftBg) | flagBg}
-}
-
-// BgGray from 0 to 24.
-func BgGray(n uint8, arg interface{}) Value {
- if val, ok := arg.(Value); ok {
- return val.BgGray(n)
- }
- if n > 23 {
- n = 23
- }
- return value{value: arg, color: (Color(n+232) << shiftBg) | flagBg}
-}
diff --git a/vendor/github.com/magefile/mage/sh/cmd.go b/vendor/github.com/magefile/mage/sh/cmd.go
index 35d232a4..312de65a 100644
--- a/vendor/github.com/magefile/mage/sh/cmd.go
+++ b/vendor/github.com/magefile/mage/sh/cmd.go
@@ -89,14 +89,14 @@ func OutputWith(env map[string]string, cmd string, args ...string) (string, erro
return strings.TrimSuffix(buf.String(), "\n"), err
}
-// Exec executes the command, piping its stderr to mage's stderr and
-// piping its stdout to the given writer. If the command fails, it will return
-// an error that, if returned from a target or mg.Deps call, will cause mage to
-// exit with the same code as the command failed with. Env is a list of
-// environment variables to set when running the command, these override the
-// current environment variables set (which are also passed to the command). cmd
-// and args may include references to environment variables in $FOO format, in
-// which case these will be expanded before the command is run.
+// Exec executes the command, piping its stdout and stderr to the given
+// writers. If the command fails, it will return an error that, if returned
+// from a target or mg.Deps call, will cause mage to exit with the same code as
+// the command failed with. Env is a list of environment variables to set when
+// running the command, these override the current environment variables set
+// (which are also passed to the command). cmd and args may include references
+// to environment variables in $FOO format, in which case these will be
+// expanded before the command is run.
//
// Ran reports if the command ran (rather than was not found or not executable).
// Code reports the exit code the command returned if it ran. If err == nil, ran
diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
index 39bbcf00..d569c0c9 100644
--- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go
+++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
@@ -1,5 +1,5 @@
-//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine
-// +build darwin freebsd openbsd netbsd dragonfly
+//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine
+// +build darwin freebsd openbsd netbsd dragonfly hurd
// +build !appengine
package isatty
diff --git a/vendor/github.com/pterm/pterm/.gitignore b/vendor/github.com/pterm/pterm/.gitignore
index e4354651..dc83dde7 100644
--- a/vendor/github.com/pterm/pterm/.gitignore
+++ b/vendor/github.com/pterm/pterm/.gitignore
@@ -15,7 +15,7 @@
vendor/
# This is where we test stuff
-/experimenting/
+/experimenting/*
/.history
/.vscode
diff --git a/vendor/github.com/pterm/pterm/.golangci.yml b/vendor/github.com/pterm/pterm/.golangci.yml
index 57ba35d8..a964631f 100644
--- a/vendor/github.com/pterm/pterm/.golangci.yml
+++ b/vendor/github.com/pterm/pterm/.golangci.yml
@@ -28,7 +28,6 @@ linters:
- gosec
- govet
- ineffassign
- - interfacer
- unconvert
- gosimple
- godox
diff --git a/vendor/github.com/pterm/pterm/CHANGELOG.md b/vendor/github.com/pterm/pterm/CHANGELOG.md
deleted file mode 100644
index a782a0c1..00000000
--- a/vendor/github.com/pterm/pterm/CHANGELOG.md
+++ /dev/null
@@ -1,1213 +0,0 @@
-
-## [Unreleased]
-
-### Bug Fixes
-- **table:** fixed panic when multiple lines contained color in a single row
-
-
-
-## [v0.12.55] - 2023-03-04
-### Features
-- **table:** multiline support for table printer
-- **table:** multiline support for table printer
-
-### Code Refactoring
-- **table:** fixed linting
-
-
-
-## [v0.12.54] - 2023-01-22
-### Bug Fixes
-- **tree:** print top node [#443](https://github.com/pterm/pterm/issues/443)
-
-
-
-## [v0.12.53] - 2023-01-05
-### Features
-- **color:** added `color.ToStyle()`
-- **color:** added `color.ToStyle()`
-- **progressbar:** added optional title to `Start` method
-
-### Bug Fixes
-- **prefix:** fixed line numbers in different print functions
-
-
-
-## [v0.12.52] - 2023-01-05
-### Features
-- **multiselect:** added theme support for checkmarks
-- **multiselect:** added theme support for checkmarks
-
-### Test
-- **multiselect:** fixed test
-
-### Code Refactoring
-- **progressbar:** make add more safe
-
-
-
-## [v0.12.51] - 2022-12-24
-### Bug Fixes
-- Make sure the confirm printer can clean up after Ctrl+C
-
-
-
-## [v0.12.50] - 2022-11-22
-### Bug Fixes
-- revert original test & add new test
-- slice bounds out of range on select printer
-
-
-
-## [v0.12.49] - 2022-10-03
-
-
-## [v0.12.48] - 2022-10-02
-### Features
-- custom select/confirm key for interactive printer
-- add flag to disable filter/search for interactive printer
-
-
-
-## [v0.12.47] - 2022-09-19
-### Features
-- adding interactive continue printer
-
-### Bug Fixes
-- typo
-- append the selected value to the prompt
-
-### Code Refactoring
-- ignore invalid custom handles
-- initiazile handles on getSuffix
-- comment format
-- address renaming PR comments
-- show full handles by default
-- use a map for the options
-
-### Reverts
-- refactor: use a map for the options
-
-
-
-## [v0.12.46] - 2022-09-05
-### Features
-- **putils:** add `CenterText` in putils
-
-### Bug Fixes
-- **textinput:** fixed overwriting the default values
-
-
-
-## [v0.12.45] - 2022-07-26
-### Bug Fixes
-- make sure the interactive printers can cleanup after Ctrl+C
-- the interactive confirm answers should match the confirm/reject text
-
-### Test
-- add tests for custom answers
-
-
-
-## [v0.12.44] - 2022-07-22
-
-
-## [v0.12.43] - 2022-07-17
-### Bug Fixes
-- **spinner:** fix line didn't clear properly
-- **table:** fixed column length calculation for Chinese strings
-
-
-
-## [v0.12.42] - 2022-06-21
-### Features
-- **input:** added text input printer
-
-
-
-## [v0.12.41] - 2022-04-12
-
-
-## [v0.12.40] - 2022-03-28
-### Features
-- added a custom writer for all printers
-
-
-
-## [v0.12.39] - 2022-03-18
-### Features
-- use fallback color in `BigTextPrinter` when `RGB` is not supported
-
-### Test
-- fix `BigTextPrinter` test
-- removed `testdata`
-- removed snapshot testing
-
-
-
-## [v0.12.38] - 2022-03-09
-### Features
-- added `NewLettersFromStringWithRGB`
-- added `NewLettersFromStringWithRGB`
-
-### Test
-- **bigtext:** fix formatting error in bigtext test
-
-
-
-## [v0.12.37] - 2022-02-17
-### Features
-- **progressbar:** Add option to set the `MaxWidth` of the progressbar
-
-### Test
-- **progressbar:** added 100% test coverage for new features
-
-### Code Refactoring
-- **putils:** Improved styling
-
-
-
-## [v0.12.36] - 2022-02-01
-### Features
-- proposal horizontal table header row and row separators fixes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators changes
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-- proposal horizontal table header row and row separators
-
-
-
-## [v0.12.35] - 2022-02-01
-### Code Refactoring
-- fix linting
-- regenerate snapshots
-
-
-
-## [v0.12.34] - 2022-01-16
-### Bug Fixes
-- **progressbar:** refresh progressbars on every PTerm print ([#302](https://github.com/pterm/pterm/issues/302))
-
-### Test
-- removed `AreaPrinter` test output
-- **table:** changed mock reader from `os.Stdin` to `outBuf`
-
-
-
-## [v0.12.33] - 2021-10-24
-### Features
-- add `PrintOnErrorf` for every `TextPrinter` ([#279](https://github.com/pterm/pterm/issues/279))
-- **coverage:** add unit test
-- **progressbar:** made updating the progressbar title easier. ([#267](https://github.com/pterm/pterm/issues/267))
-- **table:** increase test coverage
-- **table:** revamp to follow practice
-- **table:** add support for right data alignment
-
-### Bug Fixes
-- **idea:** revert unwanted config changes
-- **linter:** do linter recommendation to delete fallthrough
-
-
-
-## [v0.12.32] - 2021-10-15
-### Features
-- added `AreaPrinter.Clear()`
-
-### Bug Fixes
-- progressbar method name
-- **header:** fixed length calculation for Chinese strings
-
-### Code Refactoring
-- change bitSize size
-
-
-
-## [v0.12.31] - 2021-09-21
-### Features
-- **prefix:** added `LineNumberOffset` to `PrefixPrinter`
-
-
-
-## [v0.12.30] - 2021-08-16
-### Bug Fixes
-- **style:** resetting to previous color also resets attributes
-
-### Code Refactoring
-- adapt new testza function name
-
-
-
-## [v0.12.29] - 2021-07-19
-### Features
-- **putils:** add `PrintAverageExecutionTime`
-
-### Test
-- fix rgb error test
-- fix internal test import cycle
-- move tests into own package
-
-### Code Refactoring
-- replace `testify` with `testza`
-
-
-
-## [v0.12.28] - 2021-07-17
-### Features
-- **spinner:** add option to show a timer
-
-### Bug Fixes
-- **bar chart:** fix panic when rendering empty horizontal bar chart
-
-### Test
-- **spinner:** try to fix RawOutput text
-- **spinner:** add raw output test
-
-### Code Refactoring
-- **spinner:** better raw output logic
-- **spinner:** refactor
-
-
-
-## [v0.12.27] - 2021-07-05
-### Bug Fixes
-- **style:** fix multiline style coloring
-
-### Test
-- **style:** fix multiline style coloring
-- **style:** fix multiline style coloring
-
-
-
-## [v0.12.26] - 2021-07-01
-### Bug Fixes
-- **spinner:** Override previous text in `UpdateText`
-
-
-
-## [v0.12.25] - 2021-07-01
-### Features
-- **table:** add `Boxed` option
-
-### Test
-- add tests for boxed `TablePrinter`
-
-
-
-## [v0.12.24] - 2021-06-13
-### Features
-- **boxprinter:** replace line breaks in title with space
-- **boxprinter:** add title center position to `BoxPrinter`
-- **boxprinter:** add title & title position to `BoxPrinter`
-- **boxprinter:** add title & title position to `BoxPrinter`
-- **putils:** add `TableDataFromSeparatedValues`
-- **putils:** add `TableDataFromTSV`
-- **putils:** add `TableDataFromCSV`
-- **putils:** add function to convert TSV to `TableData`
-- **putils:** add function to convert CSV to `TableData`
-
-### Test
-- add test for putils `TableData` generation
-- **boxprinter:** add tests for title center position to `BoxPrinter`
-- **boxprinter:** add tests for title & title position
-
-### Code Refactoring
-- **boxprinter:** prefix title positions with `Title`
-- **putils:** add `rowSeparator` to `TableFromSeparatedValues`
-
-
-
-## [v0.12.23] - 2021-06-07
-### Features
-- Add util functions to create tables from slices of structs ([#217](https://github.com/pterm/pterm/issues/217))
-
-### Bug Fixes
-- **headerprinter:** don't panic if content width > terminal width
-
-### Test
-- **prefix:** `pterm.Error` default no line number shown
-
-### Code Refactoring
-- **prefix:** `pterm.Error` default no line number shown
-
-
-
-## [v0.12.22] - 2021-05-30
-### Features
-- make spinner update faster
-
-### Performance Improvements
-- improve performance of `SpinnerPrinter`
-
-
-
-## [v0.12.21] - 2021-05-30
-### Features
-- print lines above active spinners
-- **putils:** add `DownloadFileWithProgressbar`
-
-### Test
-- clear active spinners after tests complete
-
-### Code Refactoring
-- **putils:** change internal variable name
-
-
-
-## [v0.12.20] - 2021-05-29
-### Features
-- force color output by default
-
-
-
-## [v0.12.19] - 2021-05-29
-### Features
-- add `PrintOnError` for all printers and interface
-- **putils:** add `putils` package ([#206](https://github.com/pterm/pterm/issues/206))
-
-### Bug Fixes
-- **header:** fix multiline header
-
-### Test
-- add tests for all printers for `PrintOnError`
-
-### Code Refactoring
-- make `PrintOnError` return `*TextPrinter`
-- **area:** better height calculation
-
-
-
-## [v0.12.18] - 2021-05-22
-### Features
-- add `AreaPrinter`
-- **area:** add `Center` option
-- **area:** add `Fullscreen` option
-- **area:** add `GetContent` function
-- **area:** add `AreaPrinter`
-
-### Test
-- **area:** fix tests for `AreaPrinter`
-- **area:** add `AreaPrinter` tests
-
-### Code Refactoring
-- fix linting errors
-
-
-
-## [v0.12.17] - 2021-05-14
-### Bug Fixes
-- fix `pterm.Fatal.Printfln` not panicking
-- **prefix:** fix `pterm.Fatal.Printfln` not panicking and had output in debug mode
-
-### Test
-- **prefix:** add tests for `Sprintfln` and `Printfln` function when in debug mode
-
-
-
-## [v0.12.16] - 2021-05-13
-### Code Refactoring
-- **prefix:** make `PrintOnError` accept multiple inputs
-
-
-
-## [v0.12.15] - 2021-05-13
-### Features
-- add raw output mode for `BarChart`
-- add disable styling boolean option
-- **bigtext:** add raw output mode
-- **centerprinter:** add raw output mode
-- **headerprinter:** add raw output mode
-- **panelprinter:** add raw output mode
-- **paragraph:** add raw output mode
-- **prefix:** add `PrintIfError`
-- **prefix:** add raw output mode
-- **progressbar:** add raw output mode
-- **spinner:** add raw output mode
-
-### Bug Fixes
-- **prefix:** fix `PrintOnError`
-
-### Test
-- add tests with `RawOutput` enabled
-- add interface tests for `Color` and `RGB`
-- added tests for `DisableStyling` and `EnableStyling`
-
-### Code Refactoring
-- correct behaviour of Enable-/DisableStyling
-- fix variable names
-
-
-
-## [v0.12.14] - 2021-05-09
-### Features
-- **basic-text:** add `Sprintfln` and `Printfln` function
-- **boxprinter:** add `Sprintfln` and `Printfln` function
-- **centerprinter:** add `Sprintfln` and `Printfln` function
-- **color:** add `Sprintfln` and `Printfln` function
-- **header:** add `Sprintfln` and `Printfln` function
-- **paragraph:** add `Sprintfln` and `Printfln` function
-- **prefix:** add `Sprintfln` and `Printfln` function
-- **print:** add `Sprintfln` and `Printfln` function
-- **printer-interface:** add `Sprintfln` and `Printfln` to the interface
-- **rgb:** add `Sprintfln` and `Printfln` function
-- **section:** add `Sprintfln` and `Printfln` function
-
-### Bug Fixes
-- **header:** fix inline color in `Header`
-
-### Test
-- add tests for `Sprintfln` and `Printfln` function
-
-### Code Refactoring
-- refactor `Sprintfln` and `Printfln` func. for better performance
-
-### Reverts
-- ci: change color scheme for rendered examples
-
-
-
-## [v0.12.13] - 2021-04-10
-### Bug Fixes
-- **bigtext:** fix height of some characters [#180](https://github.com/pterm/pterm/issues/180)
-- **color:** make color implement `TextPrinter`
-
-### Test
-- add interface tests
-
-### Code Refactoring
-- **examples:** center the intro of `demo`
-- **examples:** add note to box printer
-
-
-
-## [v0.12.12] - 2021-03-01
-### Features
-- **prefixprinter:** Add option to show line number of caller
-
-### Code Refactoring
-- **examples:** Update `PrefixPrinter` example
-
-
-
-## [v0.12.11] - 2021-02-26
-### Code Refactoring
-- refactor print logic of `BoxPrinter`
-- refactor print logic of `CenterPrinter`
-
-
-
-## [v0.12.10] - 2021-02-26
-### Bug Fixes
-- correct `pterm.Println()` behaviour to fit to `fmt.Println()`
-
-
-
-## [v0.12.9] - 2021-02-23
-### Bug Fixes
-- correct `pterm.Println()` behaviour to fit to `fmt.Println()`
-- change terminal package import path to updated version
-
-
-
-## [v0.12.8] - 2020-12-11
-### Features
-- **boxprinter:** add `WithHorizontalString` to `BoxPrinter`
-- **boxprinter:** add `BoxPrinter`
-- **panel:** add optional border for `Panel`
-- **panelprinter:** add theme support to `PanelPrinter`
-- **theme:** add `BoxStyle` and `BoxTextStyle`
-- **theme:** add optional theme for border in `Panel`
-
-### Bug Fixes
-- revert change horizontal string change
-
-### Test
-- **boxprinter:** add test
-- **boxprinter:** test multiple lines in one box
-- **boxprinter:** add tests for `BoxPrinter`
-- **panelprinter:** add tests for adding box printer
-- **panelprinter:** add tests for optional border for `Panel`
-- **theme:** add tests for `BoxStyle` and `BoxTextStyle`
-
-### Code Refactoring
-- remove analytics
-- **boxprinter:** return theme when style is nil
-- **boxprinter:** change `DefaultBox` top and bottom padding to 0
-- **boxprinter:** fix spacing between boxes and in boxes
-- **boxprinter:** refactor code
-- **boxprinter:** change from `RenderablePrinter` to `TextPrinter`
-- **panelprinter:** add `BoxPrinter` to surround panels with a fully custom box
-- **panelprinter:** optional border for `Panel`
-
-
-
-## [v0.12.7] - 2020-11-24
-### Features
-- add values to chart
-- add horizontal `BarChartPrinter`
-- add `BarChartPrinter`
-- add `BarChartPrinter`
-- add `BarChartPrinter`
-- **theme:** add theme support to `BarChart`
-
-### Bug Fixes
-- center bars over colored labels in `BarChart`
-
-### Test
-- add tests to `BarChartPrinter`
-
-
-
-## [v0.12.6] - 2020-11-17
-### Bug Fixes
-- disabling output works as expected now ([#149](https://github.com/pterm/pterm/issues/149))
-
-
-
-## [v0.12.5] - 2020-11-17
-### Bug Fixes
-- fix `PrefixPrinter` with multiple trailing newline endings.
-
-
-
-## [v0.12.4] - 2020-11-17
-### Bug Fixes
-- fix `Printf` of `PrefixPrinter`
-
-
-
-## [v0.12.3] - 2020-11-12
-### Test
-- reduce tests
-- different test logic for rgb printing
-- add better test names for `RGB` tests
-
-
-
-## [v0.12.2] - 2020-11-05
-### Features
-- color each line separately when using multi line input
-
-### Bug Fixes
-- fix internal `GetStringMaxWidth` max width
-
-### Test
-- **basictext:** proxy print functions to DevNull
-- **progressbar:** proxy print functions to DevNull
-
-### Code Refactoring
-- use `pterm.Sprint` to print
-
-
-
-## [v0.12.1] - 2020-11-04
-### Bug Fixes
-- **panel:** Fix output when input is colored
-
-### Performance Improvements
-- **header:** calculate margin faster
-
-
-
-## [v0.12.0] - 2020-11-04
-### Features
-- **panel:** add an option to make a padding beneath `panel`
-- **panel:** add an option to make columns the same length
-
-### Bug Fixes
-- **panel:** add invalid check for `padding` in `panel`
-
-### Test
-- **bulletlist:** `BulletListItem` remove `Render` and `Srender`
-- **bulletlist:** change `BulletList` to `BulletListPrinter`
-- **panel:** add invalid check for `padding` in `panel`
-- **panel:** add test for `WithBottomPadding`
-- **panel:** add test for `WithSameColumnWidth` & multiple `panel`
-- **panel:** add test for `WithSameColumnWidth`
-- **progressbar:** change directory name `progressbar_test` to `progressbar_printer_test`
-- **progressbar:** change `Progressbar` to `ProgressbarPrinter`
-- **spinner:** change directory name `spinner_test` to `spinner_printer_test`
-- **spinner:** change `Spinner` to `SpinnerPrinter`
-- **table:** change `Table` to `TablePrinter`
-- **tree:** change `Tree` to `TreePrinter`
-
-### Code Refactoring
-- make all printer names end with `Printer` ([#134](https://github.com/pterm/pterm/issues/134))
-- **bulletlist:** remove `DefaultBulletListItem`
-- **bulletlist:** `BulletListItem` remove `Render` and `Srender`
-- **bulletlist:** `BulletListItem` is no renderable anymore
-- **bulletlist:** change `BulletList` to `BulletListPrinter`
-- **progressbar:** change `ActiveProgressbars` to `ActiveProgressbarPrinters`
-- **progressbar:** change directory name `progressbar` to `progressbar_printer`
-- **progressbar:** change `Progressbar` to `ProgressbarPrinter`
-- **spinner:** change directory name `spinner` to `spinner_printer`
-- **spinner:** change `Spinner` to `SpinnerPrinter`
-- **table:** change `Table` to `TablePrinter`
-- **tree:** change `Tree` to `TreePrinter`
-
-### BREAKING CHANGE
-
-Removed `DefaultBulletListItem`.
-
-Change names of printers which didn't end with `Printer`. Every printer name ends with `Printer` now to fit into the new naming convention.
-
-change `ActiveProgressbars` to `ActiveProgressbarPrinters`
-
-`BulletListItem` is no renderable anymore, removed `Render` and `Srender`
-
-`BulletListItem` is no renderable anymore, removed `Render` and `Srender`
-
-`BulletListItem` is no renderable anymore
-
-change `Tree` to `TreePrinter` to unify the naming scheme
-
-change `Tree` to `TreePrinter` to unify the naming scheme
-
-change `Table` to `TablePrinter` to unify the naming scheme
-
-change `Table` to `TablePrinter` to unify the naming scheme
-
-change `Spinner` to `SpinnerPrinter` to unify the naming scheme
-
-change `Spinner` to `SpinnerPrinter` to unify the naming scheme
-
-change `Progressbar` to `ProgressbarPrinter` to unify the naming scheme
-
-change `Progressbar` to `ProgressbarPrinter` to unify the naming scheme
-
-change `BulletList` to `BulletListPrinter` to unify the naming scheme
-
-change `BulletList` to `BulletListPrinter` to unify the naming scheme
-
-
-
-## [v0.11.0] - 2020-11-03
-### Features
-- add `PanelPrinter`
-
-### Bug Fixes
-- **centerprinter:** make centerprinter func return pointer
-
-### BREAKING CHANGE
-
-make centerprinter func `WithCenterEachLineSeparately` return a pointer of centerprinter
-
-
-
-## [v0.10.1] - 2020-11-02
-### Features
-- add `CenterPrinter`
-
-
-
-## [v0.10.0] - 2020-11-01
-### Features
-- make printers return errors
-- add `DisableOutput()` and `EnableOutput()` ([#108](https://github.com/pterm/pterm/issues/108))
-
-### Code Refactoring
-- ignore errors where no errors can occur
-- **theme:** change `ListTextStyle` to `BulletListTextStyle` ([#104](https://github.com/pterm/pterm/issues/104))
-- **theme:** change `ProgressbarBarStyle` to `FgCyan` ([#106](https://github.com/pterm/pterm/issues/106))
-- **theme:** change white to default color in `Theme` ([#103](https://github.com/pterm/pterm/issues/103))
-
-### BREAKING CHANGE
-
-Interface of `RenderablePrinter` and `LivePrinter` changed.
-
-The global variable `DisableOutput` was renamed to `Output`.
-
-
-
-## [v0.9.3] - 2020-10-31
-### Features
-- add a levelList converter for TreeListPrinter
-- add `TreeListPrinter` as a renderable printer
-- add `TreeListPrinter` as a renderable printer
-- **theme:** add theme support for `Tree`
-
-### Test
-- **tree:** add `Tree` tests
-
-### Code Refactoring
-- clean up `Tree`
-- **theme:** change `TreeTextStyle` to `FgDefault`
-- **tree:** add Indent to control the spacing between levels and changed docs(examples)
-- **tree:** add more spacing between levels
-- **tree:** refactor `Tree` code and write tests for `Tree`
-- **tree:** refactor `Tree` code and write tests for `Tree`
-- **tree:** refactor `Tree` code
-- **tree:** refactor `Tree` code
-- **tree:** refactor `Tree` code
-
-
-
-## [v0.9.2] - 2020-10-29
-### Features
-- add option to disable and enable colors
-
-
-
-## [v0.9.1] - 2020-10-27
-### Code Refactoring
-- make the prefix of `Info` smaller again
-
-
-
-## [v0.9.0] - 2020-10-27
-### Features
-- add `Debug` `PrefixPrinter`
-- add support for enabling and disabling debug messages
-
-### Bug Fixes
-- progressbar disappears when done and something is printed after
-
-### Test
-- add debugger tests to `PrefixPrinter`
-- add progressbar tests
-
-### Code Refactoring
-- remove `UpdateDelay` from `Progressbar`
-- change `NewList` to `NewBulletList`
-- change `NewList` to `NewBulletList`
-- deprecate `UpdateDelay` in `Progressbar`
-
-### BREAKING CHANGE
-
-Removed `UpdateDelay` from `Progressbar`. It's no longer used. The Progressbar automatically updates on every change to the current value.
-
-Changed `NewList` to `NewBulletList`.
-
-
-
-## [v0.8.1] - 2020-10-26
-### Features
-- add fade from one RGB over several RGBs to another RGB
-
-### Code Refactoring
-- refactor doc
-- refactor code
-
-
-
-## [v0.8.0] - 2020-10-24
-### Features
-- add `BigTextPrinter` ([#75](https://github.com/pterm/pterm/issues/75))
-- use level of section printer
-- add `BulletListPrinter` ([#67](https://github.com/pterm/pterm/issues/67))
-
-### Test
-- test that `%s` won't fail to print
-
-### Code Refactoring
-- make `BigTextPrinter` release ready
-- change `LineCharacter` to `BarCharacter` ([#70](https://github.com/pterm/pterm/issues/70))
-
-### BREAKING CHANGE
-
-Changed `LineCharacter` to `BarCharacter`.
-
-
-
-## [v0.7.0] - 2020-10-20
-### Features
-- **progressbar:** add RemoveWhenDone
-
-### Bug Fixes
-- make theme accept pointer styles
-- make Spinner accept pointer Style
-- make WithMessageStyle accept Style pointer
-- add nil check to SectionPrinter Style
-- section printer Style to pointer
-
-### Test
-- add tests color and style
-- add tests to root print functions
-- add tests to progressbar
-- add tests to terminal
-- add tests to theme
-- fix internal percentage test
-- add tests to Spinner
-- add tests for TablePrinter
-- special tests for special statements
-- complete PrefixPrinter tests
-- add PrefixPrinter tests
-- rename HeaderPrinter tests
-- complete HeaderPrinter tests
-- add ParagraphPrinter tests
-- add HeaderPrinter tests
-- make unit test system check different types
-- add SectionPrinter tests
-- implement test utils
-- add rgb tests
-
-### Code Refactoring
-- use log output
-- remove obsolete if
-- fit progressbar to new percentage calculation method
-- make fatal panic
-- rename parameters
-- don't show empty line when removing a progressbar
-
-
-
-## [v0.6.1] - 2020-10-20
-### Bug Fixes
-- fix RGB methods
-
-
-
-## [v0.6.0] - 2020-10-19
-### Features
-- add BasicTextPrinter
-- add theme support to section and table printer
-- add theme support to spinner
-- add theme support to headers
-- add template support for progressbars
-- add default theme
-
-### Test
-- **benchmark:** fix spinner benchmark
-
-### Code Refactoring
-- make printers accept pointers to styles
-- remove emojis to comply with cross-platform policy
-- change LivePrinter interface to pointer output
-- change TextPrinter interface to pointer output
-
-### BREAKING CHANGE
-
-All printers only accept pointers as any `Style` attribute.
-
-LivePrinter now requires to return a pointer.
-
-TextPrinter now requires to return a pointer.
-
-
-
-## [v0.5.1] - 2020-10-14
-### Features
-- add ability to disable output ([#44](https://github.com/pterm/pterm/issues/44))
-- add `Srender` to `RenderPrinter` interface
-- add csv table support ([#42](https://github.com/pterm/pterm/issues/42))
-- add HEX to RGB converter in `RGB` ([#41](https://github.com/pterm/pterm/issues/41))
-- add theme to generated animations
-- add color fade example ([#38](https://github.com/pterm/pterm/issues/38))
-- implement `TextPrinter` into `RGB`
-- implement color fade to `Progressbar` ([#37](https://github.com/pterm/pterm/issues/37))
-- add color fade function and `RBG` ([#34](https://github.com/pterm/pterm/issues/34))
-- change `Section` style
-
-### Code Refactoring
-- declare function name as `WithCSVReader`
-
-
-
-## [v0.5.0] - 2020-10-08
-### Features
-- implement `LivePrinter` in `Spinner`
-- add `BottomPadding` to `SectionPrinter`
-- add `RenderPrinter` interface
-- implement `LivePrinter` in `Progressbar`
-- add `LivePrinter` interface
-- add `TablePrinter` ([#27](https://github.com/pterm/pterm/issues/27))
-- add `ParagraphPrinter` ([#24](https://github.com/pterm/pterm/issues/24))
-
-### Test
-- add `Print` equals `Sprint` tests for `GenericPrinter`
-- add `Spinner` benchmarks
-
-### Code Refactoring
-- rename spinner_printer.go to spinner.go
-- rename `GenericPrinter` to `TextPrinter`
-
-### BREAKING CHANGE
-
-The `GenericPrinter` is now called `TextPrinter`.
-
-
-
-## [v0.4.1] - 2020-10-07
-
-
-## [v0.4.0] - 2020-10-07
-### Features
-- add `Add` to `Style`
-- add options shorthands to `SectionPrinter`
-
-### Test
-- ignore writer close errors in stdout capture
-
-### Code Refactoring
-- use `Style` instead of colors
-- refactor function parameters to fit expectation
-- rename `RemoveColors` to `RemoveColorFromString`
-
-### BREAKING CHANGE
-
-use `Style` instead of colors
-
-Refactor function parameters to fit expectation.
-Affects: `WithStyle(colors -> style)`, `WithScope(string, colors -> scope)`
-
-rename `RemoveColors` to `RemoveColorFromString`
-
-
-
-## [v0.3.2] - 2020-10-06
-### Features
-- add `SectionPrinter`
-
-### Bug Fixes
-- fix `Sprintf` function of `HeaderPrinter`
-
-### Test
-- add tests for `HeaderPrinter` and `SectionPrinter`
-
-
-
-## [v0.3.1] - 2020-10-06
-### Features
-- add `BarFiller` to `Progressbar`
-
-### Test
-- fix import cycle
-- change to inbuilt `SetDefaultOutput` option
-- add more benchmarks
-- add benchmarks
-- add tests to `GenericPrinter` and default print methods
-
-### Code Refactoring
-- set default `BarFiller` to space
-- move tests directly into `pterm` module
-
-
-
-## [v0.3.0] - 2020-10-05
-### Bug Fixes
-- fix `WithXYZ(b ...bool)` to detect booleans correctly
-
-### Code Refactoring
-- remove `Version` constant
-- change `WithXXX(b bool)` to `WithXXX(b ...bool)`
-- change `SetXXX` to `WithXXX`
-- change `Header` to `DefaultHeader`
-
-### BREAKING CHANGE
-
-remove `Version` constant
-
-rename `SetXXX` to `WithXXX`
-
-rename `Header` to `DefaultHeader`
-
-
-
-## [v0.2.4] - 2020-10-04
-### Bug Fixes
-- `Printf` works again
-
-
-
-## [v0.2.3] - 2020-10-04
-### Features
-- automatically print above `Progressbar`
-
-### Code Refactoring
-- remove goroutine from `Progressbar`
-
-
-
-## [v0.2.2] - 2020-10-04
-### Features
-- add `Fatal` printer
-
-
-
-## [v0.2.1] - 2020-10-04
-### Features
-- make progressbar configurable
-- add percentage helper
-- add `RemoveColors`
-- add `Progressbar` ([#5](https://github.com/pterm/pterm/issues/5))
-- add `Progressbar`
-- add fatal to `PrefixPrinter` ([#4](https://github.com/pterm/pterm/issues/4))
-- **progressbar:** fade percentage color according to value
-
-### Code Refactoring
-- bump version to "v0.2.1"
-
-
-
-## [v0.2.0] - 2020-09-30
-### Features
-- change style of `Description` printer
-- add color in color support
-- add `RemoveWhenDone` to `Spinner`
-- add multiline support to `PrefixPrinter`
-- add `UpdateText` to spinner
-
-### Bug Fixes
-- spinners spin evenly when multiple spinners are started
-
-### Performance Improvements
-- improve spinner performance
-
-### Code Refactoring
-- bump version to "v0.2.0"
-- change `WithXXX` to `SetXXX`
-- removed `Println` aliases
-
-### BREAKING CHANGE
-
-every `WithXXX` is renamed to `SetXXX`
-
-remove `GetFormattedMessage` from `PrefixPrinter`
-
-removed `Println` aliases
-
-
-
-## [v0.1.0] - 2020-09-28
-### Features
-- add spinners
-- shorten printer names and add builder methods to printers
-- add `Printo` to override printed text
-- add `FullWidth` to `HeaderPrinter`
-- add terminal size detection
-
-### Code Refactoring
-- bump version to "v0.1.0"
-- consistent example code for `Printo`
-- better comments for `Printo`
-- simplify `HeaderPrinter`
-
-### BREAKING CHANGE
-
-printer names changed
-
-removed `Header` and put it's content directly into `HeaderPrinter`
-
-
-
-## [v0.0.1] - 2020-09-21
-### Features
-- add aliases to default printers
-- add header example
-- integrate ci
-- add `HeaderPrinter`
-- add exported version variable
-- add example `override-default-printer`
-- change prefix text color to `LightWhite`
-
-### Bug Fixes
-- header should now work in CI
-
-### Code Refactoring
-- bump version to "v0.0.1"
-- refactor project
-- add comments to functions
-
-
-
-## v0.0.0 - 2020-09-18
-### Features
-- add changelog template
-- configs
-- initial commit
-
-
-[Unreleased]: https://github.com/pterm/pterm/compare/v0.12.55...HEAD
-[v0.12.55]: https://github.com/pterm/pterm/compare/v0.12.54...v0.12.55
-[v0.12.54]: https://github.com/pterm/pterm/compare/v0.12.53...v0.12.54
-[v0.12.53]: https://github.com/pterm/pterm/compare/v0.12.52...v0.12.53
-[v0.12.52]: https://github.com/pterm/pterm/compare/v0.12.51...v0.12.52
-[v0.12.51]: https://github.com/pterm/pterm/compare/v0.12.50...v0.12.51
-[v0.12.50]: https://github.com/pterm/pterm/compare/v0.12.49...v0.12.50
-[v0.12.49]: https://github.com/pterm/pterm/compare/v0.12.48...v0.12.49
-[v0.12.48]: https://github.com/pterm/pterm/compare/v0.12.47...v0.12.48
-[v0.12.47]: https://github.com/pterm/pterm/compare/v0.12.46...v0.12.47
-[v0.12.46]: https://github.com/pterm/pterm/compare/v0.12.45...v0.12.46
-[v0.12.45]: https://github.com/pterm/pterm/compare/v0.12.44...v0.12.45
-[v0.12.44]: https://github.com/pterm/pterm/compare/v0.12.43...v0.12.44
-[v0.12.43]: https://github.com/pterm/pterm/compare/v0.12.42...v0.12.43
-[v0.12.42]: https://github.com/pterm/pterm/compare/v0.12.41...v0.12.42
-[v0.12.41]: https://github.com/pterm/pterm/compare/v0.12.40...v0.12.41
-[v0.12.40]: https://github.com/pterm/pterm/compare/v0.12.39...v0.12.40
-[v0.12.39]: https://github.com/pterm/pterm/compare/v0.12.38...v0.12.39
-[v0.12.38]: https://github.com/pterm/pterm/compare/v0.12.37...v0.12.38
-[v0.12.37]: https://github.com/pterm/pterm/compare/v0.12.36...v0.12.37
-[v0.12.36]: https://github.com/pterm/pterm/compare/v0.12.35...v0.12.36
-[v0.12.35]: https://github.com/pterm/pterm/compare/v0.12.34...v0.12.35
-[v0.12.34]: https://github.com/pterm/pterm/compare/v0.12.33...v0.12.34
-[v0.12.33]: https://github.com/pterm/pterm/compare/v0.12.32...v0.12.33
-[v0.12.32]: https://github.com/pterm/pterm/compare/v0.12.31...v0.12.32
-[v0.12.31]: https://github.com/pterm/pterm/compare/v0.12.30...v0.12.31
-[v0.12.30]: https://github.com/pterm/pterm/compare/v0.12.29...v0.12.30
-[v0.12.29]: https://github.com/pterm/pterm/compare/v0.12.28...v0.12.29
-[v0.12.28]: https://github.com/pterm/pterm/compare/v0.12.27...v0.12.28
-[v0.12.27]: https://github.com/pterm/pterm/compare/v0.12.26...v0.12.27
-[v0.12.26]: https://github.com/pterm/pterm/compare/v0.12.25...v0.12.26
-[v0.12.25]: https://github.com/pterm/pterm/compare/v0.12.24...v0.12.25
-[v0.12.24]: https://github.com/pterm/pterm/compare/v0.12.23...v0.12.24
-[v0.12.23]: https://github.com/pterm/pterm/compare/v0.12.22...v0.12.23
-[v0.12.22]: https://github.com/pterm/pterm/compare/v0.12.21...v0.12.22
-[v0.12.21]: https://github.com/pterm/pterm/compare/v0.12.20...v0.12.21
-[v0.12.20]: https://github.com/pterm/pterm/compare/v0.12.19...v0.12.20
-[v0.12.19]: https://github.com/pterm/pterm/compare/v0.12.18...v0.12.19
-[v0.12.18]: https://github.com/pterm/pterm/compare/v0.12.17...v0.12.18
-[v0.12.17]: https://github.com/pterm/pterm/compare/v0.12.16...v0.12.17
-[v0.12.16]: https://github.com/pterm/pterm/compare/v0.12.15...v0.12.16
-[v0.12.15]: https://github.com/pterm/pterm/compare/v0.12.14...v0.12.15
-[v0.12.14]: https://github.com/pterm/pterm/compare/v0.12.13...v0.12.14
-[v0.12.13]: https://github.com/pterm/pterm/compare/v0.12.12...v0.12.13
-[v0.12.12]: https://github.com/pterm/pterm/compare/v0.12.11...v0.12.12
-[v0.12.11]: https://github.com/pterm/pterm/compare/v0.12.10...v0.12.11
-[v0.12.10]: https://github.com/pterm/pterm/compare/v0.12.9...v0.12.10
-[v0.12.9]: https://github.com/pterm/pterm/compare/v0.12.8...v0.12.9
-[v0.12.8]: https://github.com/pterm/pterm/compare/v0.12.7...v0.12.8
-[v0.12.7]: https://github.com/pterm/pterm/compare/v0.12.6...v0.12.7
-[v0.12.6]: https://github.com/pterm/pterm/compare/v0.12.5...v0.12.6
-[v0.12.5]: https://github.com/pterm/pterm/compare/v0.12.4...v0.12.5
-[v0.12.4]: https://github.com/pterm/pterm/compare/v0.12.3...v0.12.4
-[v0.12.3]: https://github.com/pterm/pterm/compare/v0.12.2...v0.12.3
-[v0.12.2]: https://github.com/pterm/pterm/compare/v0.12.1...v0.12.2
-[v0.12.1]: https://github.com/pterm/pterm/compare/v0.12.0...v0.12.1
-[v0.12.0]: https://github.com/pterm/pterm/compare/v0.11.0...v0.12.0
-[v0.11.0]: https://github.com/pterm/pterm/compare/v0.10.1...v0.11.0
-[v0.10.1]: https://github.com/pterm/pterm/compare/v0.10.0...v0.10.1
-[v0.10.0]: https://github.com/pterm/pterm/compare/v0.9.3...v0.10.0
-[v0.9.3]: https://github.com/pterm/pterm/compare/v0.9.2...v0.9.3
-[v0.9.2]: https://github.com/pterm/pterm/compare/v0.9.1...v0.9.2
-[v0.9.1]: https://github.com/pterm/pterm/compare/v0.9.0...v0.9.1
-[v0.9.0]: https://github.com/pterm/pterm/compare/v0.8.1...v0.9.0
-[v0.8.1]: https://github.com/pterm/pterm/compare/v0.8.0...v0.8.1
-[v0.8.0]: https://github.com/pterm/pterm/compare/v0.7.0...v0.8.0
-[v0.7.0]: https://github.com/pterm/pterm/compare/v0.6.1...v0.7.0
-[v0.6.1]: https://github.com/pterm/pterm/compare/v0.6.0...v0.6.1
-[v0.6.0]: https://github.com/pterm/pterm/compare/v0.5.1...v0.6.0
-[v0.5.1]: https://github.com/pterm/pterm/compare/v0.5.0...v0.5.1
-[v0.5.0]: https://github.com/pterm/pterm/compare/v0.4.1...v0.5.0
-[v0.4.1]: https://github.com/pterm/pterm/compare/v0.4.0...v0.4.1
-[v0.4.0]: https://github.com/pterm/pterm/compare/v0.3.2...v0.4.0
-[v0.3.2]: https://github.com/pterm/pterm/compare/v0.3.1...v0.3.2
-[v0.3.1]: https://github.com/pterm/pterm/compare/v0.3.0...v0.3.1
-[v0.3.0]: https://github.com/pterm/pterm/compare/v0.2.4...v0.3.0
-[v0.2.4]: https://github.com/pterm/pterm/compare/v0.2.3...v0.2.4
-[v0.2.3]: https://github.com/pterm/pterm/compare/v0.2.2...v0.2.3
-[v0.2.2]: https://github.com/pterm/pterm/compare/v0.2.1...v0.2.2
-[v0.2.1]: https://github.com/pterm/pterm/compare/v0.2.0...v0.2.1
-[v0.2.0]: https://github.com/pterm/pterm/compare/v0.1.0...v0.2.0
-[v0.1.0]: https://github.com/pterm/pterm/compare/v0.0.1...v0.1.0
-[v0.0.1]: https://github.com/pterm/pterm/compare/v0.0.0...v0.0.1
diff --git a/vendor/github.com/pterm/pterm/README.md b/vendor/github.com/pterm/pterm/README.md
index ccfbce73..c7a37292 100644
--- a/vendor/github.com/pterm/pterm/README.md
+++ b/vendor/github.com/pterm/pterm/README.md
@@ -35,13 +35,17 @@
+
+
+
+
-Show Demo Code
+Show Demo Code
@@ -74,44 +78,44 @@ Make sure to run this command inside your project, when you're using go modules
go get github.com/pterm/pterm
```
-If you want to create a CLI tool, make sure to check out our [cli-template](https://github.com/pterm/cli-template),
-which features automatic website generation, automatic deployments, a custom CI-System and much more!
-
## ⭐ Main Features
-|Feature|Description|
-|-------|-----------|
-|🪀 Easy to use |Our first priority is to keep PTerm as easy to use as possible.
With many [examples](#-examples) for each individual component, getting started with PTerm is extremely easy.
All components are similar in design and implement interfaces to simplify mixing individual components together.|
-|🤹♀️ Cross-Platform |We take special precautions to ensure that PTerm works on as many operating systems and terminals as possible.
Whether it's `Windows CMD`, `macOS iTerm2` or in the backend (for example inside a `GitHub Action` or other CI systems), PTerm **guarantees** beautiful output!|
-|🧪 Well tested |PTerm has a 100% test coverage, which means that every line of code inside PTerm gets tested automatically
We test PTerm continuously. However, since a human cannot test everything all the time, we have our own test system with which we currently run **`28774`**automated tests to ensure that PTerm has no bugs. |
-|✨ Consistent Colors|PTerm uses the [ANSI color scheme](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) which is widely used by terminals to ensure consistent colors in different terminal themes.
If that's not enough, PTerm can be used to access the full RGB color scheme (16 million colors) in terminals that support `TrueColor`.|
-|📚 Component system|PTerm consists of many components, called `Printers`, which can be used individually or together to generate pretty console output.|
-|🛠 Configurable|PTerm can be used by without any configuration. However, you can easily configure each component with little code, so everyone has the freedom to design their own terminal output.|
-|✏ Documentation |To view the official documentation of the latest release, you can go to the automatically generated page of [pkg.go.dev](https://pkg.go.dev/github.com/pterm/pterm#section-documentation) This documentation is very technical and includes every method that can be used in PTerm.
**For an easy start we recommend that you take a look at the [examples section](#-examples).** Here you can see pretty much every feature of PTerm with example code. The animations of the examples are automatically updated as soon as something changes in PTerm.|
+| Feature | Description |
+|------------------|-----------------------------------------------------|
+| 🪀 Easy to use | PTerm emphasizes ease of use, with [examples](#-examples) and consistent component design. |
+| 🤹♀️ Cross-Platform | PTerm works on various OS and terminals, including `Windows CMD`, `macOS iTerm2`, and in CI systems like `GitHub Actions`. |
+| 🧪 Well tested | A high test coverage and `28774` automated tests ensure PTerm's reliability. |
+| ✨ Consistent Colors | PTerm uses the [ANSI color scheme](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) for uniformity and supports `TrueColor` for advanced terminals. |
+| 📚 Component system | PTerm's flexible `Printers` can be used individually or combined to generate beautiful console output. |
+| 🛠 Configurable | PTerm is ready to use without configuration but allows easy customization for unique terminal output. |
+| ✏ Documentation | Access comprehensive docs on [pkg.go.dev](https://pkg.go.dev/github.com/pterm/pterm#section-documentation) and view practical examples in the [examples section](#-examples). |
+
+### Printers (Components)
-### Printers (Components)
+
+| Feature | Feature | Feature | Feature | Feature |
+| :-------: | :-------: | :-------: | :-------: | :-------: |
+| Area
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/area) |Barchart
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/barchart) |Basictext
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/basictext) |Bigtext
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/bigtext) |Box
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/box) |
+| Bulletlist
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/bulletlist) |Center
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/center) |Coloring
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/coloring) |Header
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/header) |Heatmap
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/heatmap) |
+| Interactive confirm
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_confirm) |Interactive continue
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_continue) |Interactive multiselect
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_multiselect) |Interactive select
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_select) |Interactive textinput
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_textinput) |
+| Logger
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/logger) |Multiple-live-printers
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/multiple-live-printers) |Panel
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/panel) |Paragraph
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/paragraph) |Prefix
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/prefix) |
+| Progressbar
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/progressbar) |Section
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/section) |Slog
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/slog) |Spinner
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/spinner) |Style
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/style) |
+| Table
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/table) |Theme
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/theme) |Tree
[(Examples)](https://github.com/pterm/pterm/tree/master/_examples/tree) | | |
+
+
+
+
+---
+
+
+
+### 🦸♂️ Sponsors
-|Feature|Examples| - |Feature|Examples|
-|-------|--------|---|-----|--------|
-|Bar Charts|[Examples](https://github.com/pterm/pterm/tree/master/_examples/barchart)|-|RGB|[Examples](https://github.com/pterm/pterm/tree/master/_examples/coloring)|
-|BigText|[Examples](https://github.com/pterm/pterm/tree/master/_examples/bigtext)|-|Sections|[Examples](https://github.com/pterm/pterm/tree/master/_examples/section)|
-|Box|[Examples](https://github.com/pterm/pterm/tree/master/_examples/box)|-|Spinners|[Examples](https://github.com/pterm/pterm/tree/master/_examples/spinner)|
-|Bullet Lists|[Examples](https://github.com/pterm/pterm/tree/master/_examples/bulletlist)|-|Trees|[Examples](https://github.com/pterm/pterm/tree/master/_examples/tree)|
-|Centered|[Examples](https://github.com/pterm/pterm/tree/master/_examples/center)|-|Theming|[Examples](https://github.com/pterm/pterm/tree/master/_examples/theme)|
-|Colors|[Examples](https://github.com/pterm/pterm/tree/master/_examples/coloring)|-|Tables|[Examples](https://github.com/pterm/pterm/tree/master/_examples/table)|
-|Headers|[Examples](https://github.com/pterm/pterm/tree/master/_examples/header)|-|Styles|[Examples](https://github.com/pterm/pterm/tree/master/_examples/style)|
-|Panels|[Examples](https://github.com/pterm/pterm/tree/master/_examples/panel)|-|Area|[Examples](https://github.com/pterm/pterm/tree/master/_examples/area)|
-|Paragraphs|[Examples](https://github.com/pterm/pterm/tree/master/_examples/paragraph)|-|||
-|Prefixes|[Examples](https://github.com/pterm/pterm/tree/master/_examples/prefix)|-|||
-|Progress Bars|[Examples](https://github.com/pterm/pterm/tree/master/_examples/progressbar)|-|||
-
-### 🦸♂️ Supporters
-
-|-|User|💸|
-|---|---|---|
-|![Jens Lauterbach](https://avatars.githubusercontent.com/u/1292368?s=25)|[@jenslauterbach](https://github.com/jenslauterbach)|25$|
+
+
+---
@@ -146,18 +150,37 @@ import (
"time"
"github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
)
func main() {
+ // Print an informational message using PTerm's Info printer.
+ // This message will stay in place while the area updates.
pterm.Info.Println("The previous text will stay in place, while the area updates.")
- pterm.Print("\n\n") // Add two new lines as spacer.
- area, _ := pterm.DefaultArea.WithCenter().Start() // Start the Area printer, with the Center option.
+ // Print two new lines as spacer.
+ pterm.Print("\n\n")
+
+ // Start the Area printer from PTerm's DefaultArea, with the Center option.
+ // The Area printer allows us to update a specific area of the console output.
+ // The returned 'area' object is used to control the area updates.
+ area, _ := pterm.DefaultArea.WithCenter().Start()
+
+ // Loop 10 times to update the area with the current time.
for i := 0; i < 10; i++ {
- str, _ := pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString(time.Now().Format("15:04:05"))).Srender() // Save current time in str.
- area.Update(str) // Update Area contents.
+ // Get the current time, format it as "15:04:05" (hour:minute:second), and convert it to a string.
+ // Then, create a BigText from the time string using PTerm's DefaultBigText and putils NewLettersFromString.
+ // The Srender() function is used to save the BigText as a string.
+ str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender()
+
+ // Update the Area contents with the current time string.
+ area.Update(str)
+
+ // Sleep for a second before the next update.
time.Sleep(time.Second)
}
+
+ // Stop the Area printer after all updates are done.
area.Stop()
}
@@ -165,9 +188,9 @@ func main() {
-### barchart/demo
+### area/center
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/center/animation.svg)
@@ -177,37 +200,37 @@ func main() {
package main
import (
+ "time"
+
"github.com/pterm/pterm"
)
func main() {
- positiveBars := pterm.Bars{
- pterm.Bar{
- Label: "Bar 1",
- Value: 5,
- },
- pterm.Bar{
- Label: "Bar 2",
- Value: 3,
- },
- pterm.Bar{
- Label: "Longer Label",
- Value: 7,
- },
+ // Start a new default area in the center of the terminal.
+ // The Start() function returns the created area and an error.
+ area, _ := pterm.DefaultArea.WithCenter().Start()
+
+ // Loop 5 times to simulate a dynamic update.
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count.
+ // The Sprintf function is used to format the string.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second to simulate a time-consuming task.
+ time.Sleep(time.Second)
}
- pterm.Info.Println("Chart example with positive only values (bars use 100% of chart area)")
- _ = pterm.DefaultBarChart.WithBars(positiveBars).Render()
- _ = pterm.DefaultBarChart.WithHorizontal().WithBars(positiveBars).Render()
+ // Stop the area after all updates are done.
+ area.Stop()
}
```
-### barchart/mixed-values
+### area/default
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/mixed-values/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/default/animation.svg)
@@ -217,45 +240,38 @@ func main() {
package main
import (
+ "time"
+
"github.com/pterm/pterm"
)
func main() {
- mixedBars := pterm.Bars{
- pterm.Bar{
- Label: "Bar 1",
- Value: 2,
- },
- pterm.Bar{
- Label: "Bar 2",
- Value: -3,
- },
- pterm.Bar{
- Label: "Bar 3",
- Value: -2,
- },
- pterm.Bar{
- Label: "Bar 4",
- Value: 5,
- },
- pterm.Bar{
- Label: "Longer Label",
- Value: 7,
- },
+ // Start a new default area and get a reference to it.
+ // The second return value is an error which is ignored here.
+ area, _ := pterm.DefaultArea.Start()
+
+ // Loop 5 times
+ for i := 0; i < 5; i++ {
+ // Update the content of the area dynamically.
+ // Here we're just displaying the current count.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second before the next update.
+ time.Sleep(time.Second)
}
- pterm.DefaultSection.Println("Chart example with mixed values (note screen space usage in case when ABSOLUTE values of negative and positive parts are differ too much)")
- _ = pterm.DefaultBarChart.WithBars(mixedBars).WithShowValue().Render()
- _ = pterm.DefaultBarChart.WithHorizontal().WithBars(mixedBars).WithShowValue().Render()
+ // Stop the area after all updates are done.
+ // This will clean up and free resources used by the area.
+ area.Stop()
}
```
-### barchart/negative-values
+### area/dynamic-chart
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/negative-values/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/dynamic-chart/animation.svg)
@@ -265,37 +281,51 @@ func main() {
package main
import (
+ "time"
+
"github.com/pterm/pterm"
)
func main() {
- negativeBars := pterm.Bars{
- pterm.Bar{
- Label: "Bar 1",
- Value: -5,
- },
- pterm.Bar{
- Label: "Bar 2",
- Value: -3,
- },
- pterm.Bar{
- Label: "Longer Label",
- Value: -7,
- },
+ // Start a new fullscreen centered area.
+ // This area will be used to display the bar chart.
+ area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
+ // Ensure the area stops updating when we're done.
+ defer area.Stop()
+
+ // Loop to update the bar chart 10 times.
+ for i := 0; i < 10; i++ {
+ // Create a new bar chart with dynamic bars.
+ // The bars will change based on the current iteration.
+ barchart := pterm.DefaultBarChart.WithBars(dynamicBars(i))
+ // Render the bar chart to a string.
+ // This string will be used to update the area.
+ content, _ := barchart.Srender()
+ // Update the area with the new bar chart.
+ area.Update(content)
+ // Wait for half a second before the next update.
+ time.Sleep(500 * time.Millisecond)
}
+}
- pterm.Info.Println("Chart example with negative only values (bars use 100% of chart area)")
- _ = pterm.DefaultBarChart.WithBars(negativeBars).WithShowValue().Render()
- _ = pterm.DefaultBarChart.WithHorizontal().WithBars(negativeBars).WithShowValue().Render()
+// dynamicBars generates a set of bars for the bar chart.
+// The bars will change based on the current iteration.
+func dynamicBars(i int) pterm.Bars {
+ return pterm.Bars{
+ {Label: "A", Value: 10}, // A static bar.
+ {Label: "B", Value: 20 * i}, // A bar that grows with each iteration.
+ {Label: "C", Value: 30}, // Another static bar.
+ {Label: "D", Value: 40 + i}, // A bar that grows slowly with each iteration.
+ }
}
```
-### basictext/demo
+### area/fullscreen
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/basictext/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/fullscreen/animation.svg)
@@ -304,25 +334,38 @@ func main() {
```go
package main
-import "github.com/pterm/pterm"
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
func main() {
- // A BasicText printer is used to print text, without special formatting.
- // As it implements the TextPrinter interface, you can use it in combination with other printers.
- pterm.DefaultBasicText.Println("Default basic text printer.")
- pterm.DefaultBasicText.Println("Can be used in any" + pterm.LightMagenta(" TextPrinter ") + "context.")
- pterm.DefaultBasicText.Println("For example to resolve progressbars and spinners.")
- // If you just want to print text, you should use this instead:
- // pterm.Println("Hello, World!")
+ // Start a new fullscreen area. This will return an area instance and an error.
+ // The underscore (_) is used to ignore the error.
+ area, _ := pterm.DefaultArea.WithFullscreen().Start()
+
+ // Loop 5 times to update the area content.
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count.
+ // The Sprintf function is used to format the string.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second before the next update.
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done.
+ area.Stop()
}
```
-### bigtext/demo
+### area/fullscreen-center
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/fullscreen-center/animation.svg)
@@ -332,34 +375,38 @@ func main() {
package main
import (
+ "time"
+
"github.com/pterm/pterm"
- "github.com/pterm/pterm/putils"
)
func main() {
- // Print a large text with the LetterStyle from the standard theme.
- // Useful for title screens.
- pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Render()
+ // Initialize a new PTerm area with fullscreen and center options
+ // The Start() function returns the created area and an error (ignored here)
+ area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
- // Print a large text with differently colored letters.
- pterm.DefaultBigText.WithLetters(
- putils.LettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgCyan)),
- putils.LettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
- Render()
+ // Loop 5 times to demonstrate dynamic content update
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count
+ // The Sprintf function is used to format the string with the count
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
- // LettersFromStringWithRGB can be used to create a large text with a specific RGB color.
- pterm.DefaultBigText.WithLetters(
- putils.LettersFromStringWithRGB("PTerm", pterm.NewRGB(255, 215, 0))).
- Render()
+ // Pause for a second
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done
+ // This will clear the area and return the terminal to its normal state
+ area.Stop()
}
```
-### box/demo
+### barchart/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/demo/animation.svg)
@@ -368,30 +415,39 @@ func main() {
```go
package main
-import "github.com/pterm/pterm"
+import (
+ "github.com/pterm/pterm"
+)
func main() {
- pterm.Info.Println("This might not be rendered correctly on GitHub,\nbut it will work in a real terminal.\nThis is because GitHub does not use a monospaced font by default for SVGs")
+ // Define the bars for the chart
+ bars := []pterm.Bar{
+ {Label: "Bar 1", Value: 5},
+ {Label: "Bar 2", Value: 3},
+ {Label: "Longer Label", Value: 7},
+ }
- panel1 := pterm.DefaultBox.Sprint("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt\nut labore et dolore\nmagna aliqua.")
- panel2 := pterm.DefaultBox.WithTitle("title").Sprint("Ut enim ad minim veniam,\nquis nostrud exercitation\nullamco laboris\nnisi ut aliquip\nex ea commodo\nconsequat.")
- panel3 := pterm.DefaultBox.WithTitle("bottom center title").WithTitleBottomCenter().Sprint("Duis aute irure\ndolor in reprehenderit\nin voluptate velit esse cillum\ndolore eu fugiat\nnulla pariatur.")
+ // Print an informational message
+ pterm.Info.Println("Chart example with positive only values (bars use 100% of chart area)")
- panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
- {{Data: panel1}, {Data: panel2}},
- {{Data: panel3}},
- }).Srender()
+ // Create a bar chart with the defined bars and render it
+ // The DefaultBarChart is used as a base, and the bars are added with the WithBars option
+ // The Render function is then called to display the chart
+ pterm.DefaultBarChart.WithBars(bars).Render()
- pterm.DefaultBox.WithTitle("Lorem Ipsum").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(panels)
+ // Create a horizontal bar chart with the defined bars and render it
+ // The DefaultBarChart is used as a base, the chart is made horizontal with the WithHorizontal option, and the bars are added with the WithBars option
+ // The Render function is then called to display the chart
+ pterm.DefaultBarChart.WithHorizontal().WithBars(bars).Render()
}
```
-### bulletlist/customized
+### barchart/custom-height
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/customized/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/custom-height/animation.svg)
@@ -400,26 +456,37 @@ func main() {
```go
package main
-import (
- "github.com/pterm/pterm"
-)
+import "github.com/pterm/pterm"
func main() {
- // Print a customized list with different styles and levels.
- pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{
- {Level: 0, Text: "Blue", TextStyle: pterm.NewStyle(pterm.FgBlue), BulletStyle: pterm.NewStyle(pterm.FgRed)},
- {Level: 1, Text: "Green", TextStyle: pterm.NewStyle(pterm.FgGreen), Bullet: "-", BulletStyle: pterm.NewStyle(pterm.FgLightWhite)},
- {Level: 2, Text: "Cyan", TextStyle: pterm.NewStyle(pterm.FgCyan), Bullet: ">", BulletStyle: pterm.NewStyle(pterm.FgYellow)},
- }).Render()
+ // Define a slice of Bar structs. Each struct represents a bar in the chart.
+ // The Label field is the name of the bar and the Value field is the height of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create and render a bar chart with the defined bars and a height of 5.
+ // The WithBars method is used to set the bars of the chart.
+ // The WithHeight method is used to set the height of the chart.
+ // The Render method is used to display the chart in the terminal.
+ pterm.DefaultBarChart.WithBars(bars).WithHeight(5).Render()
}
```
-### bulletlist/demo
+### barchart/custom-width
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/custom-width/animation.svg)
@@ -428,34 +495,35 @@ func main() {
```go
package main
-import (
- "github.com/pterm/pterm"
- "github.com/pterm/pterm/putils"
-)
+import "github.com/pterm/pterm"
func main() {
- // Print a list with different levels.
- // Useful to generate lists automatically from data.
- pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{
- {Level: 0, Text: "Level 0"},
- {Level: 1, Text: "Level 1"},
- {Level: 2, Text: "Level 2"},
- }).Render()
+ // Define the data for the bar chart
+ barData := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
- // Convert a text to a list and print it.
- putils.BulletListFromString(`0
- 1
- 2
- 3`, " ").Render()
+ // Create a bar chart with the defined data
+ // The chart is horizontal and has a width of 5
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithWidth(5).Render()
}
```
-### center/demo
+### barchart/default
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/center/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/default/animation.svg)
@@ -467,22 +535,33 @@ package main
import "github.com/pterm/pterm"
func main() {
- pterm.DefaultCenter.Println("This text is centered!\nIt centeres the whole block by default.\nIn that way you can do stuff like this:")
-
- // Generate BigLetters
- s, _ := pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString("PTerm")).Srender()
- pterm.DefaultCenter.Println(s) // Print BigLetters with the default CenterPrinter
+ // Define the data for the bar chart. Each bar is represented by a `pterm.Bar` struct.
+ // The `Label` field represents the label of the bar, and the `Value` field represents the value of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
- pterm.DefaultCenter.WithCenterEachLineSeparately().Println("This text is centered!\nBut each line is\ncentered\nseparately")
+ // Use the `DefaultBarChart` from the `pterm` package to create a bar chart.
+ // The `WithBars` method is used to set the bars of the chart.
+ // The `Render` method is used to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).Render()
}
```
-### coloring/demo
+### barchart/horizontal
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/horizontal/animation.svg)
@@ -494,39 +573,32 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print all colors
-
- pterm.DefaultTable.WithData([][]string{
- {pterm.FgBlack.Sprint("Black"), pterm.FgRed.Sprint("Red"), pterm.FgGreen.Sprint("Green"), pterm.FgYellow.Sprint("Yellow")},
- {"", pterm.FgLightRed.Sprint("Light Red"), pterm.FgLightGreen.Sprint("Light Green"), pterm.FgLightYellow.Sprint("Light Yellow")},
- {pterm.BgBlack.Sprint("Black"), pterm.BgRed.Sprint("Red"), pterm.BgGreen.Sprint("Green"), pterm.BgYellow.Sprint("Yellow")},
- {"", pterm.BgLightRed.Sprint("Light Red"), pterm.BgLightGreen.Sprint("Light Green"), pterm.BgLightYellow.Sprint("Light Yellow")},
- {pterm.FgBlue.Sprint("Blue"), pterm.FgMagenta.Sprint("Magenta"), pterm.FgCyan.Sprint("Cyan"), pterm.FgWhite.Sprint("White")},
- {pterm.FgLightBlue.Sprint("Light Blue"), pterm.FgLightMagenta.Sprint("Light Magenta"), pterm.FgLightCyan.Sprint("Light Cyan"), pterm.FgLightWhite.Sprint("Light White")},
- {pterm.BgBlue.Sprint("Blue"), pterm.BgMagenta.Sprint("Magenta"), pterm.BgCyan.Sprint("Cyan"), pterm.BgWhite.Sprint("White")},
- {pterm.BgLightBlue.Sprint("Light Blue"), pterm.BgLightMagenta.Sprint("Light Magenta"), pterm.BgLightCyan.Sprint("Light Cyan"), pterm.BgLightWhite.Sprint("Light White")},
- }).Render()
-
- pterm.Println()
-
- // Print different colored words.
- pterm.Println(pterm.Red("Hello, ") + pterm.Green("World") + pterm.Cyan("!"))
- pterm.Println(pterm.Red("Even " + pterm.Cyan("nested ") + pterm.Green("colors ") + "are supported!"))
-
- pterm.Println()
+ // Define the data for the bar chart
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
- // Or print colors as a style
- style := pterm.NewStyle(pterm.BgRed, pterm.FgLightGreen, pterm.Bold)
- style.Println("This text uses a style and is bold and light green with a red background!")
+ // Create a bar chart with the defined data
+ // The chart is displayed horizontally
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(bars).WithHorizontal().Render()
}
```
-### coloring/disable-output
+### barchart/horizontal-show-value
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/disable-output/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/horizontal-show-value/animation.svg)
@@ -538,27 +610,32 @@ package main
import "github.com/pterm/pterm"
func main() {
- for i := 0; i < 15; i++ {
- switch i {
- case 5:
- pterm.Info.Println("Disabled Output!")
- pterm.DisableOutput()
- case 10:
- pterm.EnableOutput()
- pterm.Info.Println("Enabled Output!")
- }
-
- pterm.Printf("Printing something... [%d/%d]\n", i, 15)
+ // Define the data for the bar chart
+ barData := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
}
+
+ // Create a bar chart with the defined data
+ // The chart is horizontal and displays the value of each bar
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithShowValue().Render()
}
```
-### coloring/fade-colors
+### barchart/mixed-values
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-colors/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/mixed-values/animation.svg)
@@ -572,26 +649,38 @@ import (
)
func main() {
- // Print info.
- pterm.Info.Println("RGB colors only work in Terminals which support TrueColor.")
+ // Define a set of bars for the chart.
+ // Each bar has a label and a value.
+ bars := []pterm.Bar{
+ {Label: "Bar 1", Value: 2},
+ {Label: "Bar 2", Value: -3},
+ {Label: "Bar 3", Value: -2},
+ {Label: "Bar 4", Value: 5},
+ {Label: "Longer Label", Value: 7},
+ }
+
+ // Print a section header.
+ // This is useful for separating different parts of the output.
+ pterm.DefaultSection.Println("Chart example with mixed values (note screen space usage in case when ABSOLUTE values of negative and positive parts are differ too much)")
- from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
- to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients end point.
+ // Create a bar chart with the defined bars.
+ // The chart will display the value of each bar.
+ // The Render() function is called to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
- // For loop over the range of the terminal height.
- for i := 0; i < pterm.GetTerminalHeight()-2; i++ {
- // Print string which is colored with the faded RGB value.
- from.Fade(0, float32(pterm.GetTerminalHeight()-2), float32(i), to).Println("Hello, World!")
- }
+ // Create a horizontal bar chart with the same bars.
+ // The chart will display the value of each bar.
+ // The Render() function is called to display the chart.
+ pterm.DefaultBarChart.WithHorizontal().WithBars(bars).WithShowValue().Render()
}
```
-### coloring/fade-multiple-colors
+### barchart/negative-values
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-multiple-colors/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/negative-values/animation.svg)
@@ -601,44 +690,39 @@ func main() {
package main
import (
- "strings"
-
"github.com/pterm/pterm"
)
func main() {
- from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
- to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
- to2 := pterm.NewRGB(255, 0, 0) // This RGB value is used as the gradients second point.
- to3 := pterm.NewRGB(0, 255, 0) // This RGB value is used as the gradients third point.
- to4 := pterm.NewRGB(255, 255, 255) // This RGB value is used as the gradients end point.
-
- str := "RGB colors only work in Terminals which support TrueColor."
- strs := strings.Split(str, "")
- var fadeInfo string // String which will be used to print info.
- // For loop over the range of the string length.
- for i := 0; i < len(str); i++ {
- // Append faded letter to info string.
- fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ // Define a set of bars with negative values.
+ // Each bar is represented by a struct with a label and a value.
+ negativeBars := pterm.Bars{
+ {Label: "Bar 1", Value: -5},
+ {Label: "Bar 2", Value: -3},
+ {Label: "Longer Label", Value: -7},
}
- // Print info.
- pterm.Info.Println(fadeInfo)
+ // Print an informational message to the console.
+ pterm.Info.Println("Chart example with negative only values (bars use 100% of chart area)")
- // For loop over the range of the terminal height.
- for i := 0; i < pterm.GetTerminalHeight()-2; i++ {
- // Print string which is colored with the faded RGB value.
- from.Fade(0, float32(pterm.GetTerminalHeight()-2), float32(i), to, to2, to3, to4).Println("Hello, World!")
- }
+ // Create a vertical bar chart with the defined bars.
+ // The WithShowValue() option is used to display the value of each bar in the chart.
+ // The Render() method is called to draw the chart.
+ _ = pterm.DefaultBarChart.WithBars(negativeBars).WithShowValue().Render()
+
+ // Create a horizontal bar chart with the same bars.
+ // The WithHorizontal() option is used to orient the chart horizontally.
+ // The WithShowValue() option and Render() method are used in the same way as before.
+ _ = pterm.DefaultBarChart.WithHorizontal().WithBars(negativeBars).WithShowValue().Render()
}
```
-### coloring/override-default-printers
+### barchart/show-value
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/override-default-printers/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/show-value/animation.svg)
@@ -650,26 +734,35 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print default error.
- pterm.Error.Println("This is the default Error")
-
- // Customize default error.
- pterm.Error.Prefix = pterm.Prefix{
- Text: "OVERRIDE",
- Style: pterm.NewStyle(pterm.BgCyan, pterm.FgRed),
+ // Define a slice of bars for the bar chart. Each bar is represented by a struct
+ // with a Label and a Value. The Label is a string that represents the name of the bar,
+ // and the Value is an integer that represents the height of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
}
- // Print new default error.
- pterm.Error.Println("This is the default Error after the prefix was overridden")
+ // Create a bar chart with the defined bars using the DefaultBarChart object from PTerm.
+ // Chain the WithBars method to set the bars of the chart.
+ // Chain the WithShowValue method to display the value of each bar on the chart.
+ // Finally, call the Render method to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
}
```
-### coloring/print-color-rgb
+### basictext/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/print-color-rgb/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/basictext/demo/animation.svg)
@@ -681,20 +774,24 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print strings with a custom RGB color.
- // NOTICE: This only works with terminals which support TrueColor.
- pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
- pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
- pterm.NewRGB(201, 144, 30).Println("This text is printed with a custom RGB!")
+ // The DefaultBasicText is a basic text printer provided by PTerm.
+ // It is used to print text without any special formatting.
+ pterm.DefaultBasicText.Println("Default basic text printer.")
+
+ // The DefaultBasicText can be used in any context that requires a TextPrinter.
+ // Here, we're using it with the LightMagenta function to color a portion of the text.
+ pterm.DefaultBasicText.Println("Can be used in any" + pterm.LightMagenta(" TextPrinter ") + "context.")
+
+ // The DefaultBasicText is also useful for resolving progress bars and spinners.
}
```
-### demo/demo
+### bigtext/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/demo/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/demo/animation.svg)
@@ -704,275 +801,1493 @@ func main() {
package main
import (
- "flag"
- "math/rand"
- "reflect"
- "strconv"
- "strings"
- "time"
-
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
-// Speed the demo up, by setting this flag.
-// Usefull for debugging.
-// Example:
-// go run main.go -speedup
-var speedup = flag.Bool("speedup", false, "Speed up the demo")
-var skipIntro = flag.Bool("skip-intro", false, "Skips the intro")
-var second = time.Second
+func main() {
+ // Create a large text with the LetterStyle from the standard theme.
+ // This is useful for creating title screens.
+ pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Render()
-var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
- "pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+ // Create a large text with differently colored letters.
+ // Here, the first letter 'P' is colored cyan and the rest 'Term' is colored light magenta.
+ // This can be used to highlight specific parts of the text.
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
+ putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle()),
+ ).Render()
-func main() {
- setup() // Setup the demo (flags etc.)
+ // Create a large text with a specific RGB color.
+ // This can be used when you need a specific color that is not available in the standard colors.
+ // Here, the color is gold (RGB: 255, 215, 0).
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithRGB("PTerm", pterm.NewRGB(255, 215, 0)),
+ ).Render()
+}
- // Show intro
- if !*skipIntro {
- introScreen()
- clear()
- }
+```
- showcase("Progress bar", 2, func() {
- pb, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
- for i := 0; i < pb.Total; i++ {
- pb.UpdateTitle("Installing " + pseudoProgramList[i])
- if pseudoProgramList[i] == "pseudo-minecraft" {
- pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+
+
+### bigtext/colored
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/colored/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Initialize a big text display with the letters "P" and "Term"
+ // "P" is displayed in cyan and "Term" is displayed in light magenta
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
+ putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle())).
+ Render() // Render the big text to the terminal
+}
+
+```
+
+
+
+### bigtext/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Define the text to be rendered
+ var text = "PTerm"
+
+ // Convert the text into a format suitable for PTerm
+ var letters = putils.LettersFromString(text)
+
+ // Render the text using PTerm's default big text style
+ pterm.DefaultBigText.WithLetters(letters).Render()
+}
+
+```
+
+
+
+### box/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print an informational message.
+ pterm.Info.Println("This might not be rendered correctly on GitHub,\nbut it will work in a real terminal.\nThis is because GitHub does not use a monospaced font by default for SVGs")
+
+ // Create three panels with text, some of them with titles.
+ // The panels are created using the DefaultBox style.
+ panel1 := pterm.DefaultBox.Sprint("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt\nut labore et dolore\nmagna aliqua.")
+ panel2 := pterm.DefaultBox.WithTitle("title").Sprint("Ut enim ad minim veniam,\nquis nostrud exercitation\nullamco laboris\nnisi ut aliquip\nex ea commodo\nconsequat.")
+ panel3 := pterm.DefaultBox.WithTitle("bottom center title").WithTitleBottomCenter().Sprint("Duis aute irure\ndolor in reprehenderit\nin voluptate velit esse cillum\ndolore eu fugiat\nnulla pariatur.")
+
+ // Combine the panels into a layout using the DefaultPanel style.
+ // The layout is a 2D grid, with each row being an array of panels.
+ // In this case, the first row contains panel1 and panel2, and the second row contains only panel3.
+ panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
+ {{Data: panel1}, {Data: panel2}},
+ {{Data: panel3}},
+ }).Srender()
+
+ // Print the panels layout inside a box with a title.
+ // The box is created using the DefaultBox style, with the title positioned at the bottom right.
+ pterm.DefaultBox.WithTitle("Lorem Ipsum").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(panels)
+}
+
+```
+
+
+
+### box/custom-padding
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/custom-padding/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with custom padding options and print "Hello, World!" inside it.
+ pterm.DefaultBox.WithRightPadding(10).WithLeftPadding(10).WithTopPadding(2).WithBottomPadding(2).Println("Hello, World!")
+}
+
+```
+
+
+
+### box/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with PTerm and print a message in it.
+ // The DefaultBox.Println method automatically starts, prints the message, and stops the box.
+ pterm.DefaultBox.Println("Hello, World!")
+}
+
+```
+
+
+
+### box/title
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/title/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with specified padding
+ paddedBox := pterm.DefaultBox.WithLeftPadding(4).WithRightPadding(4).WithTopPadding(1).WithBottomPadding(1)
+
+ // Define a title for the box
+ title := pterm.LightRed("I'm a box!")
+
+ // Create boxes with the title positioned differently and containing different content
+ box1 := paddedBox.WithTitle(title).Sprint("Hello, World!\n 1") // Title at default position (top left)
+ box2 := paddedBox.WithTitle(title).WithTitleTopCenter().Sprint("Hello, World!\n 2") // Title at top center
+ box3 := paddedBox.WithTitle(title).WithTitleTopRight().Sprint("Hello, World!\n 3") // Title at top right
+ box4 := paddedBox.WithTitle(title).WithTitleBottomRight().Sprint("Hello, World!\n 4") // Title at bottom right
+ box5 := paddedBox.WithTitle(title).WithTitleBottomCenter().Sprint("Hello, World!\n 5") // Title at bottom center
+ box6 := paddedBox.WithTitle(title).WithTitleBottomLeft().Sprint("Hello, World!\n 6") // Title at bottom left
+ box7 := paddedBox.WithTitle(title).WithTitleTopLeft().Sprint("Hello, World!\n 7") // Title at top left
+
+ // Render the boxes in a panel layout
+ pterm.DefaultPanel.WithPanels([][]pterm.Panel{
+ {{box1}, {box2}, {box3}},
+ {{box4}, {box5}, {box6}},
+ {{box7}},
+ }).Render()
+}
+
+```
+
+
+
+### bulletlist/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Define a list of bullet list items with different levels.
+ bulletListItems := []pterm.BulletListItem{
+ {Level: 0, Text: "Level 0"}, // Level 0 item
+ {Level: 1, Text: "Level 1"}, // Level 1 item
+ {Level: 2, Text: "Level 2"}, // Level 2 item
+ }
+
+ // Use the default bullet list style to render the list items.
+ pterm.DefaultBulletList.WithItems(bulletListItems).Render()
+
+ // Define a string with different levels of indentation.
+ text := `0
+ 1
+ 2
+ 3`
+
+ // Convert the indented string to a bullet list and render it.
+ putils.BulletListFromString(text, " ").Render()
+}
+
+```
+
+
+
+### bulletlist/customized
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/customized/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define a list of bullet list items with different styles and levels.
+ bulletListItems := []pterm.BulletListItem{
+ {
+ Level: 0, // Level 0 (top level)
+ Text: "Blue", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgBlue), // Text color
+ BulletStyle: pterm.NewStyle(pterm.FgRed), // Bullet color
+ },
+ {
+ Level: 1, // Level 1 (sub-item)
+ Text: "Green", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgGreen), // Text color
+ Bullet: "-", // Custom bullet symbol
+ BulletStyle: pterm.NewStyle(pterm.FgLightWhite), // Bullet color
+ },
+ {
+ Level: 2, // Level 2 (sub-sub-item)
+ Text: "Cyan", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgCyan), // Text color
+ Bullet: ">", // Custom bullet symbol
+ BulletStyle: pterm.NewStyle(pterm.FgYellow), // Bullet color
+ },
+ }
+
+ // Create a bullet list with the defined items and render it.
+ pterm.DefaultBulletList.WithItems(bulletListItems).Render()
+}
+
+```
+
+
+
+### center/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/center/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Print a block of text centered in the terminal
+ pterm.DefaultCenter.Println("This text is centered!\nIt centers the whole block by default.\nIn that way you can do stuff like this:")
+
+ // Generate BigLetters and store in 's'
+ s, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Srender()
+
+ // Print the BigLetters 's' centered in the terminal
+ pterm.DefaultCenter.Println(s)
+
+ // Print each line of the text separately centered in the terminal
+ pterm.DefaultCenter.WithCenterEachLineSeparately().Println("This text is centered!\nBut each line is\ncentered\nseparately")
+}
+
+```
+
+
+
+### coloring/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a table with different foreground and background colors.
+ pterm.DefaultTable.WithData([][]string{
+ {pterm.FgBlack.Sprint("Black"), pterm.FgRed.Sprint("Red"), pterm.FgGreen.Sprint("Green"), pterm.FgYellow.Sprint("Yellow")},
+ {"", pterm.FgLightRed.Sprint("Light Red"), pterm.FgLightGreen.Sprint("Light Green"), pterm.FgLightYellow.Sprint("Light Yellow")},
+ {pterm.BgBlack.Sprint("Black"), pterm.BgRed.Sprint("Red"), pterm.BgGreen.Sprint("Green"), pterm.BgYellow.Sprint("Yellow")},
+ {"", pterm.BgLightRed.Sprint("Light Red"), pterm.BgLightGreen.Sprint("Light Green"), pterm.BgLightYellow.Sprint("Light Yellow")},
+ {pterm.FgBlue.Sprint("Blue"), pterm.FgMagenta.Sprint("Magenta"), pterm.FgCyan.Sprint("Cyan"), pterm.FgWhite.Sprint("White")},
+ {pterm.FgLightBlue.Sprint("Light Blue"), pterm.FgLightMagenta.Sprint("Light Magenta"), pterm.FgLightCyan.Sprint("Light Cyan"), pterm.FgLightWhite.Sprint("Light White")},
+ {pterm.BgBlue.Sprint("Blue"), pterm.BgMagenta.Sprint("Magenta"), pterm.BgCyan.Sprint("Cyan"), pterm.BgWhite.Sprint("White")},
+ {pterm.BgLightBlue.Sprint("Light Blue"), pterm.BgLightMagenta.Sprint("Light Magenta"), pterm.BgLightCyan.Sprint("Light Cyan"), pterm.BgLightWhite.Sprint("Light White")},
+ }).Render() // Render the table.
+
+ pterm.Println()
+
+ // Print words in different colors.
+ pterm.Println(pterm.Red("Hello, ") + pterm.Green("World") + pterm.Cyan("!"))
+ pterm.Println(pterm.Red("Even " + pterm.Cyan("nested ") + pterm.Green("colors ") + "are supported!"))
+
+ pterm.Println()
+
+ // Create a new style with a red background, light green foreground, and bold text.
+ style := pterm.NewStyle(pterm.BgRed, pterm.FgLightGreen, pterm.Bold)
+ // Print text using the created style.
+ style.Println("This text uses a style and is bold and light green with a red background!")
+}
+
+```
+
+
+
+### coloring/disable-output
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/disable-output/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Loop from 0 to 14
+ for i := 0; i < 15; i++ {
+ switch i {
+ case 5:
+ // At the 5th iteration, print a message and disable the output
+ pterm.Info.Println("Disabled Output!")
+ pterm.DisableOutput()
+ case 10:
+ // At the 10th iteration, enable the output and print a message
+ pterm.EnableOutput()
+ pterm.Info.Println("Enabled Output!")
+ }
+
+ // Print a progress message for each iteration
+ pterm.Printf("Printing something... [%d/%d]\n", i, 15)
+ }
+}
+
+```
+
+
+
+### coloring/fade-colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Print an informational message.
+ pterm.Info.Println("RGB colors only work in Terminals which support TrueColor.")
+
+ // Define the start and end points for the color gradient.
+ startColor := pterm.NewRGB(0, 255, 255) // Cyan
+ endColor := pterm.NewRGB(255, 0, 255) // Magenta
+
+ // Get the terminal height to determine the gradient range.
+ terminalHeight := pterm.GetTerminalHeight()
+
+ // Loop over the range of the terminal height to create a color gradient.
+ for i := 0; i < terminalHeight-2; i++ {
+ // Calculate the fade factor for the current step in the gradient.
+ fadeFactor := float32(i) / float32(terminalHeight-2)
+
+ // Create a color that represents the current step in the gradient.
+ currentColor := startColor.Fade(0, 1, fadeFactor, endColor)
+
+ // Print a string with the current color.
+ currentColor.Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### coloring/fade-colors-rgb-style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-colors-rgb-style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB colors
+ white := pterm.NewRGB(255, 255, 255)
+ grey := pterm.NewRGB(128, 128, 128)
+ black := pterm.NewRGB(0, 0, 0)
+ red := pterm.NewRGB(255, 0, 0)
+ purple := pterm.NewRGB(255, 0, 255)
+ green := pterm.NewRGB(0, 255, 0)
+
+ // Define strings to be printed
+ str1 := "RGB colors only work in Terminals which support TrueColor."
+ str2 := "The background and foreground colors can be customized individually."
+ str3 := "Styles can also be applied. For example: Bold or Italic."
+
+ // Print first string with color fading from white to purple
+ printFadedString(str1, white, purple, grey, black)
+
+ // Print second string with color fading from purple to red
+ printFadedString(str2, black, purple, red, red)
+
+ // Print third string with color fading from white to green and style changes
+ printStyledString(str3, white, green, red, black)
+}
+
+// printFadedString prints a string with color fading effect
+func printFadedString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
+ strs := strings.Split(str, "")
+ var result string
+ for i := 0; i < len(str); i++ {
+ // Create a style with color fading effect
+ style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
+ // Append styled letter to result string
+ result += style.Sprint(strs[i])
+ }
+ pterm.Println(result)
+}
+
+// printStyledString prints a string with color fading and style changes
+func printStyledString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
+ strs := strings.Split(str, "")
+ var result string
+ boldStr := strings.Split("Bold", "")
+ italicStr := strings.Split("Italic", "")
+ bold, italic := 0, 0
+ for i := 0; i < len(str); i++ {
+ // Create a style with color fading effect
+ style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
+ // Check if the next letters are "Bold" or "Italic" and add the corresponding style
+ if bold < len(boldStr) && i+len(boldStr)-bold <= len(strs) && strings.Join(strs[i:i+len(boldStr)-bold], "") == strings.Join(boldStr[bold:], "") {
+ style = style.AddOptions(pterm.Bold)
+ bold++
+ } else if italic < len(italicStr) && i+len(italicStr)-italic < len(strs) && strings.Join(strs[i:i+len(italicStr)-italic], "") == strings.Join(italicStr[italic:], "") {
+ style = style.AddOptions(pterm.Italic)
+ italic++
+ }
+ // Append styled letter to result string
+ result += style.Sprint(strs[i])
+ }
+ pterm.Println(result)
+}
+
+```
+
+
+
+### coloring/fade-multiple-colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-multiple-colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB values for gradient points.
+ startColor := pterm.NewRGB(0, 255, 255)
+ firstPoint := pterm.NewRGB(255, 0, 255)
+ secondPoint := pterm.NewRGB(255, 0, 0)
+ thirdPoint := pterm.NewRGB(0, 255, 0)
+ endColor := pterm.NewRGB(255, 255, 255)
+
+ // Define the string to be printed.
+ str := "RGB colors only work in Terminals which support TrueColor."
+ strs := strings.Split(str, "")
+
+ // Initialize an empty string for the faded info.
+ var fadeInfo string
+
+ // Loop over the string length to create a gradient effect.
+ for i := 0; i < len(str); i++ {
+ // Append each character of the string with a faded color to the info string.
+ fadeInfo += startColor.Fade(0, float32(len(str)), float32(i), firstPoint).Sprint(strs[i])
+ }
+
+ // Print the info string with gradient effect.
+ pterm.Info.Println(fadeInfo)
+
+ // Get the terminal height.
+ terminalHeight := pterm.GetTerminalHeight()
+
+ // Loop over the terminal height to print "Hello, World!" with a gradient effect.
+ for i := 0; i < terminalHeight-2; i++ {
+ // Print the string with a color that fades from startColor to endColor.
+ startColor.Fade(0, float32(terminalHeight-2), float32(i), firstPoint, secondPoint, thirdPoint, endColor).Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### coloring/override-default-printers
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/override-default-printers/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a default error message with PTerm's built-in Error style.
+ pterm.Error.Println("This is the default Error")
+
+ // Override the default error prefix with a new text and style.
+ pterm.Error.Prefix = pterm.Prefix{Text: "OVERRIDE", Style: pterm.NewStyle(pterm.BgCyan, pterm.FgRed)}
+
+ // Print the error message again, this time with the overridden prefix.
+ pterm.Error.Println("This is the default Error after the prefix was overridden")
+}
+
+```
+
+
+
+### coloring/print-color-rgb
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/print-color-rgb/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a new RGB color with values 178, 44, 199.
+ // This color will be used for the text.
+ pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
+
+ // Create a new RGB color with values 15, 199, 209.
+ // This color will be used for the text.
+ pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
+
+ // Create a new RGB color with values 201, 144, 30.
+ // This color will be used for the background.
+ // The 'true' argument indicates that the color is for the background.
+ pterm.NewRGB(201, 144, 30, true).Println("This text is printed with a custom RGB background!")
+}
+
+```
+
+
+
+### coloring/print-color-rgb-style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/print-color-rgb-style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB colors for foreground and background.
+ foregroundRGB := pterm.RGB{R: 187, G: 80, B: 0}
+ backgroundRGB := pterm.RGB{R: 0, G: 50, B: 123}
+
+ // Create a new RGB style with the defined foreground and background colors.
+ rgbStyle := pterm.NewRGBStyle(foregroundRGB, backgroundRGB)
+
+ // Print a string with the custom RGB style.
+ rgbStyle.Println("This text is not styled.")
+
+ // Add the 'Bold' option to the RGB style and print a string with this style.
+ rgbStyle.AddOptions(pterm.Bold).Println("This text is bold.")
+
+ // Add the 'Italic' option to the RGB style and print a string with this style.
+ rgbStyle.AddOptions(pterm.Italic).Println("This text is italic.")
+}
+
+```
+
+
+
+### demo/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/demo/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "flag"
+ "math/rand"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+// Speed the demo up, by setting this flag.
+// Usefull for debugging.
+// Example:
+//
+// go run main.go -speedup
+var speedup = flag.Bool("speedup", false, "Speed up the demo")
+var skipIntro = flag.Bool("skip-intro", false, "Skips the intro")
+var second = time.Second
+
+var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ setup() // Setup the demo (flags etc.)
+
+ // Show intro
+ if !*skipIntro {
+ introScreen()
+ clear()
+ }
+
+ showcase("Structured Logging", 5, func() {
+ logger := pterm.DefaultLogger.
+ WithLevel(pterm.LogLevelTrace)
+
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ time.Sleep(time.Second * 3)
+
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+ time.Sleep(time.Second * 3)
+
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+ time.Sleep(time.Second * 3)
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+ time.Sleep(time.Second * 3)
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+ time.Sleep(time.Second * 3)
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+ })
+
+ showcase("Progress bar", 2, func() {
+ pb, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
+ for i := 0; i < pb.Total; i++ {
+ pb.UpdateTitle("Installing " + pseudoProgramList[i])
+ if pseudoProgramList[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
} else {
pterm.Success.Println("Installing " + pseudoProgramList[i])
}
- pb.Increment()
- time.Sleep(second / 2)
+ pb.Increment()
+ time.Sleep(second / 2)
+ }
+ pb.Stop()
+ })
+
+ showcase("Spinner", 2, func() {
+ list := pseudoProgramList[7:]
+ spinner, _ := pterm.DefaultSpinner.Start("Installing stuff")
+ for i := 0; i < len(list); i++ {
+ spinner.UpdateText("Installing " + list[i])
+ if list[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+ } else {
+ pterm.Success.Println("Installing " + list[i])
+ }
+ time.Sleep(second)
+ }
+ spinner.Success()
+ })
+
+ showcase("Live Output", 2, func() {
+ pterm.Info.Println("You can use an Area to display changing output:")
+ pterm.Println()
+ area, _ := pterm.DefaultArea.WithCenter().Start() // Start the Area printer, with the Center option.
+ for i := 0; i < 10; i++ {
+ str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender() // Save current time in str.
+ area.Update(str) // Update Area contents.
+ time.Sleep(time.Second)
+ }
+ area.Stop()
+ })
+
+ showcase("Tables", 4, func() {
+ for i := 0; i < 3; i++ {
+ pterm.Println()
+ }
+ td := [][]string{
+ {"Library", "Description"},
+ {"PTerm", "Make beautiful CLIs"},
+ {"Testza", "Programmer friendly test framework"},
+ {"Cursor", "Move the cursor around the terminal"},
+ }
+ table, _ := pterm.DefaultTable.WithHasHeader().WithData(td).Srender()
+ boxedTable, _ := pterm.DefaultTable.WithHasHeader().WithData(td).WithBoxed().Srender()
+ pterm.DefaultCenter.Println(table)
+ pterm.DefaultCenter.Println(boxedTable)
+ })
+
+ showcase("TrueColor Support", 7, func() {
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+
+ str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)\n\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+ strs := strings.Split(str, "")
+ var fadeInfo string // String which will be used to print info.
+ // For loop over the range of the string length.
+ for i := 0; i < len(str); i++ {
+ // Append faded letter to info string.
+ fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ }
+ pterm.DefaultCenter.WithCenterEachLineSeparately().Println(fadeInfo)
+ })
+
+ showcase("Fully Customizable", 2, func() {
+ for i := 0; i < 4; i++ {
+ pterm.Println()
+ }
+ text := "All printers are fully customizable!"
+ area := pterm.DefaultArea.WithCenter()
+ area.Update(pterm.DefaultBox.Sprintln(text))
+ time.Sleep(second)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopLeft().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopCenter().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopRight().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomRight().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomCenter().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomLeft().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgCyan)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgRed)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgGreen)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).
+ WithBottomPadding(1).
+ WithLeftPadding(1).
+ WithRightPadding(1).
+ WithHorizontalString("═").
+ WithVerticalString("║").
+ WithBottomLeftCornerString("╗").
+ WithBottomRightCornerString("╔").
+ WithTopLeftCornerString("╝").
+ WithTopRightCornerString("╚").
+ Sprintln(text))
+ area.Stop()
+ })
+
+ showcase("Themes", 2, func() {
+ pterm.Info.Println("You can change the color theme of PTerm easily to fit your needs!\nThis is the default one:")
+ time.Sleep(second / 2)
+ // Print every value of the default theme with its own style.
+ v := reflect.ValueOf(pterm.ThemeDefault)
+ typeOfS := v.Type()
+
+ if typeOfS == reflect.TypeOf(pterm.Theme{}) {
+ for i := 0; i < v.NumField(); i++ {
+ field, ok := v.Field(i).Interface().(pterm.Style)
+ if ok {
+ field.Println(typeOfS.Field(i).Name)
+ }
+ time.Sleep(time.Millisecond * 250)
+ }
}
- pb.Stop()
})
- showcase("Spinner", 2, func() {
- list := pseudoProgramList[7:]
- spinner, _ := pterm.DefaultSpinner.Start("Installing stuff")
- for i := 0; i < len(list); i++ {
- spinner.UpdateText("Installing " + list[i])
- if list[i] == "pseudo-minecraft" {
- pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
- } else {
- pterm.Success.Println("Installing " + list[i])
- }
- time.Sleep(second)
- }
- spinner.Success()
- })
+ showcase("And much more!", 3, func() {
+ for i := 0; i < 4; i++ {
+ pterm.Println()
+ }
+ box := pterm.DefaultBox.
+ WithBottomPadding(1).
+ WithTopPadding(1).
+ WithLeftPadding(3).
+ WithRightPadding(3).
+ Sprintf("Have fun exploring %s!", pterm.Cyan("PTerm"))
+ pterm.DefaultCenter.Println(box)
+ })
+}
+
+func setup() {
+ flag.Parse()
+ if *speedup {
+ second = time.Millisecond * 200
+ }
+}
+
+func introScreen() {
+ ptermLogo, _ := pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
+ putils.LettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+ Srender()
+
+ pterm.DefaultCenter.Print(ptermLogo)
+
+ pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint("PTDP - PTerm Demo Program"))
+
+ pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
+ "\nPTerm works on nearly every terminal and operating system." +
+ "\nIt's super easy to use!" +
+ "\nIf you want, you can customize everything :)" +
+ "\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
+ "\n" +
+ "\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
+ pterm.Println()
+ introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
+ time.Sleep(second)
+ for i := 14; i > 0; i-- {
+ if i > 1 {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
+ } else {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
+ }
+ time.Sleep(second)
+ }
+ introSpinner.Stop()
+}
+
+func clear() {
+ print("\033[H\033[2J")
+}
+
+func showcase(title string, seconds int, content func()) {
+ pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithFullWidth().Println(title)
+ pterm.Println()
+ time.Sleep(second / 2)
+ content()
+ time.Sleep(second * time.Duration(seconds))
+ print("\033[H\033[2J")
+}
+
+func randomInt(min, max int) int {
+ rand.Seed(time.Now().UnixNano())
+ return rand.Intn(max-min+1) + min
+}
+
+```
+
+
+
+### header/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a default header.
+ // This uses the default settings of PTerm to print a header.
+ pterm.DefaultHeader.Println("This is the default header!")
+
+ // Print a spacer line for better readability.
+ pterm.Println()
+
+ // Print a full-width header.
+ // This uses the WithFullWidth() option of PTerm to print a header that spans the full width of the terminal.
+ pterm.DefaultHeader.WithFullWidth().Println("This is a full-width header.")
+}
+
+```
+
+
+
+### header/custom
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header/custom/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Customize the DefaultHeader with a cyan background, black text, and a margin of 15.
+ pterm.DefaultHeader.WithMargin(15).WithBackgroundStyle(pterm.NewStyle(pterm.BgCyan)).WithTextStyle(pterm.NewStyle(pterm.FgBlack)).Println("This is a custom header!")
+
+ // Define a new HeaderPrinter with a red background, black text, and a margin of 20.
+ newHeader := pterm.HeaderPrinter{
+ TextStyle: pterm.NewStyle(pterm.FgBlack),
+ BackgroundStyle: pterm.NewStyle(pterm.BgRed),
+ Margin: 20,
+ }
+
+ // Print the custom header using the new HeaderPrinter.
+ newHeader.Println("This is a custom header!")
+}
+
+```
+
+
+
+### heatmap/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap. Each sub-array represents a row in the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the labels for the X and Y axes of the heatmap.
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Create a heatmap with the defined data and axis labels, and enable RGB colors.
+ // Then render the heatmap.
+ pterm.DefaultHeatmap.WithAxisData(headerData).WithData(data).WithEnableRGB().Render()
+}
+
+```
+
+
+
+### heatmap/custom_colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message
+ pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and a legend.")
+ pterm.Println()
+
+ // Create the heatmap with the defined data and options, and render it
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(headerData).
+ WithLegend(false).
+ WithColors(pterm.BgBlue, pterm.BgRed, pterm.BgGreen, pterm.BgYellow).
+ WithLegend().
+ Render()
+}
+
+```
+
+
+
+### heatmap/custom_legend
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_legend/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
- showcase("Live Output", 2, func() {
- pterm.Info.Println("You can use an Area to display changing output:")
- pterm.Println()
- area, _ := pterm.DefaultArea.WithCenter().Start() // Start the Area printer, with the Center option.
- for i := 0; i < 10; i++ {
- str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender() // Save current time in str.
- area.Update(str) // Update Area contents.
- time.Sleep(time.Second)
- }
- area.Stop()
- })
+func main() {
+ // Define the data for the heatmap
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
- showcase("Tables", 4, func() {
- for i := 0; i < 3; i++ {
- pterm.Println()
- }
- td := [][]string{
- {"Library", "Description"},
- {"PTerm", "Make beautiful CLIs"},
- {"Testza", "Programmer friendly test framework"},
- {"Cursor", "Move the cursor around the terminal"},
- }
- table, _ := pterm.DefaultTable.WithHasHeader().WithData(td).Srender()
- boxedTable, _ := pterm.DefaultTable.WithHasHeader().WithData(td).WithBoxed().Srender()
- pterm.DefaultCenter.Println(table)
- pterm.DefaultCenter.Println(boxedTable)
- })
+ // Define the header data for the heatmap
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
- showcase("Default Prefix Printers", 5, func() {
- // Enable debug messages.
- pterm.EnableDebugMessages() // Temporarily set debug output to true, to display the debug printer.
+ // Print an informational message
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a custom legend.")
+ pterm.Println()
- pterm.Debug.Println("Hello, World!") // Print Debug.
- time.Sleep(second / 2)
- pterm.Info.Println("Hello, World!") // Print Info.
- time.Sleep(second / 2)
- pterm.Success.Println("Hello, World!") // Print Success.
- time.Sleep(second / 2)
- pterm.Warning.Println("Hello, World!") // Print Warning.
- time.Sleep(second / 2)
- pterm.Error.Println("Errors show the filename and linenumber inside the terminal!") // Print Error.
- time.Sleep(second / 2)
- pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!") // Print Error.
- time.Sleep(second / 2)
- // Temporarily set Fatal to false, so that the CI won't panic.
- pterm.Fatal.WithFatal(false).Println("Hello, World!") // Print Fatal.
+ // Create the heatmap with the defined data and options
+ // Options are chained in a single line for simplicity
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(headerData).
+ WithEnableRGB().
+ WithLegendLabel("custom").
+ WithLegendOnlyColoredCells().
+ Render() // Render the heatmap
+}
- pterm.DisableDebugMessages() // Disable debug output again.
- })
+```
- showcase("TrueColor Support", 7, func() {
- from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
- to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+
- str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)\n\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
- strs := strings.Split(str, "")
- var fadeInfo string // String which will be used to print info.
- // For loop over the range of the string length.
- for i := 0; i < len(str); i++ {
- // Append faded letter to info string.
- fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
- }
- pterm.DefaultCenter.WithCenterEachLineSeparately().Println(fadeInfo)
- })
+### heatmap/custom_rgb
- showcase("Themes", 2, func() {
- pterm.Info.Println("You can change the color theme of PTerm easily to fit your needs!\nThis is the default one:")
- time.Sleep(second / 2)
- // Print every value of the default theme with its own style.
- v := reflect.ValueOf(pterm.ThemeDefault)
- typeOfS := v.Type()
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_rgb/animation.svg)
- if typeOfS == reflect.TypeOf(pterm.Theme{}) {
- for i := 0; i < v.NumField(); i++ {
- field, ok := v.Field(i).Interface().(pterm.Style)
- if ok {
- field.Println(typeOfS.Field(i).Name)
- }
- time.Sleep(time.Millisecond * 250)
- }
- }
- })
+
- showcase("Fully Customizale", 2, func() {
- for i := 0; i < 4; i++ {
- pterm.Println()
- }
- text := "All printers are fully customizable!"
- area := pterm.DefaultArea.WithCenter()
- area.Update(pterm.DefaultBox.Sprintln(text))
- time.Sleep(second)
- area.Update(pterm.DefaultBox.WithTopPadding(1).Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopLeft().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopCenter().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopRight().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomRight().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomCenter().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomLeft().Sprintln(text))
- time.Sleep(second / 3)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgCyan)).Sprintln(text))
- time.Sleep(second / 5)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgRed)).Sprintln(text))
- time.Sleep(second / 5)
- area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgGreen)).Sprintln(text))
- time.Sleep(second / 5)
- area.Update(pterm.DefaultBox.WithTopPadding(1).
- WithBottomPadding(1).
- WithLeftPadding(1).
- WithRightPadding(1).
- WithHorizontalString("═").
- WithVerticalString("║").
- WithBottomLeftCornerString("╗").
- WithBottomRightCornerString("╔").
- WithTopLeftCornerString("╝").
- WithTopRightCornerString("╚").
- Sprintln(text))
- area.Stop()
- })
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap.
+ axisLabels := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
+ pterm.Println()
+
+ // Define the color range for the heatmap.
+ rgbRange := []pterm.RGB{
+ pterm.NewRGB(0, 0, 255),
+ pterm.NewRGB(255, 0, 0),
+ pterm.NewRGB(0, 255, 0),
+ pterm.NewRGB(255, 255, 0),
+ }
+
+ // Create and render the heatmap.
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(axisLabels).
+ WithEnableRGB().
+ WithRGBRange(rgbRange...).
+ Render()
+}
+
+```
+
+
+
+### heatmap/no_grid
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/no_grid/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis data for the heatmap.
+ axisData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
+ pterm.Println()
+
+ // Create the heatmap with the defined data and options, then render it.
+ pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(axisData).WithEnableRGB().WithLegend().WithGrid(false).Render()
+}
+
+```
+
+
+
+### heatmap/separated
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/separated/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap.
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and no legend.")
+ pterm.Println()
+
+ // Create the heatmap with the specified data and options, and render it.
+ pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(headerData).WithLegend(false).Render()
+}
+
+```
+
+
+
+### interactive_confirm/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_confirm/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Show an interactive confirmation dialog and get the result.
+ result, _ := pterm.DefaultInteractiveConfirm.Show()
+
+ // Print a blank line for better readability.
+ pterm.Println()
+
+ // Print the user's answer in a formatted way.
+ pterm.Info.Printfln("You answered: %s", boolToText(result))
+}
+
+// boolToText converts a boolean value to a colored text.
+// If the value is true, it returns a green "Yes".
+// If the value is false, it returns a red "No".
+func boolToText(b bool) string {
+ if b {
+ return pterm.Green("Yes")
+ }
+ return pterm.Red("No")
+}
+
+```
+
+
+
+### interactive_continue/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_continue/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
- showcase("And much more!", 3, func() {
- for i := 0; i < 4; i++ {
- pterm.Println()
- }
- box := pterm.DefaultBox.
- WithBottomPadding(1).
- WithTopPadding(1).
- WithLeftPadding(3).
- WithRightPadding(3).
- Sprintf("Have fun exploring %s!", pterm.Cyan("PTerm"))
- pterm.DefaultCenter.Println(box)
- })
+func main() {
+ // Create an interactive continue prompt with default settings
+ // This will pause the program execution until the user presses enter
+ // The message displayed is "Press 'Enter' to continue..."
+ prompt := pterm.DefaultInteractiveContinue
+
+ // Show the prompt and wait for user input
+ // The returned result is the user's input (should be empty as it's a continue prompt)
+ // The second return value is an error which is ignored here
+ result, _ := prompt.Show()
+
+ // Print a blank line for better readability
+ pterm.Println()
+
+ // Print the user's input with an info prefix
+ // As this is a continue prompt, the input should be empty
+ pterm.Info.Printfln("You answered: %s", result)
}
-func setup() {
- flag.Parse()
- if *speedup {
- second = time.Millisecond * 200
+```
+
+
+
+### interactive_multiselect/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options.
+ var options []string
+
+ // Populate the options slice with 100 options.
+ for i := 0; i < 100; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Add 5 more options to the slice, indicating the availability of fuzzy searching.
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
}
+
+ // Use PTerm's interactive multiselect to present the options to the user and capture their selections.
+ // The Show() method displays the options and waits for user input.
+ selectedOptions, _ := pterm.DefaultInteractiveMultiselect.WithOptions(options).Show()
+
+ // Print the selected options, highlighted in green.
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
-func introScreen() {
- ptermLogo, _ := pterm.DefaultBigText.WithLetters(
- putils.LettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
- putils.LettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
- Srender()
+```
- pterm.DefaultCenter.Print(ptermLogo)
+
- pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint("PTDP - PTerm Demo Program"))
+### interactive_multiselect/custom-checkmarks
- pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
- "\nPTerm works on nearly every terminal and operating system." +
- "\nIt's super easy to use!" +
- "\nIf you want, you can customize everything :)" +
- "\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
- "\n" +
- "\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
- pterm.Println()
- introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
- time.Sleep(second)
- for i := 14; i > 0; i-- {
- if i > 1 {
- introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
- } else {
- introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
- }
- time.Sleep(second)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-checkmarks/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options
+ var options []string
+
+ // Populate the options slice with 5 options
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
}
- introSpinner.Stop()
-}
-func clear() {
- print("\033[H\033[2J")
-}
+ // Create a new interactive multiselect printer with the options
+ // Disable the filter and define the checkmark symbols
+ printer := pterm.DefaultInteractiveMultiselect.
+ WithOptions(options).
+ WithFilter(false).
+ WithCheckmark(&pterm.Checkmark{Checked: pterm.Green("+"), Unchecked: pterm.Red("-")})
-func showcase(title string, seconds int, content func()) {
- pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithFullWidth().Println(title)
- pterm.Println()
- time.Sleep(second / 2)
- content()
- time.Sleep(second * time.Duration(seconds))
- print("\033[H\033[2J")
-}
+ // Show the interactive multiselect and get the selected options
+ selectedOptions, _ := printer.Show()
-func randomInt(min, max int) int {
- rand.Seed(time.Now().UnixNano())
- return rand.Intn(max-min+1) + min
+ // Print the selected options
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
```
-### header/demo
+### interactive_multiselect/custom-keys
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-keys/animation.svg)
@@ -981,22 +2296,43 @@ func randomInt(min, max int) int {
```go
package main
-import "github.com/pterm/pterm"
+import (
+ "atomicgo.dev/keyboard/keys"
+ "fmt"
+ "github.com/pterm/pterm"
+)
func main() {
- // Print a default header.
- pterm.DefaultHeader.Println("This is the default header!")
- pterm.Println() // spacer
- pterm.DefaultHeader.WithFullWidth().Println("This is a full-width header.")
+ // Initialize an empty slice to hold the options
+ var options []string
+
+ // Populate the options slice with 5 options
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Create a new interactive multiselect printer with the options
+ // Disable the filter and set the keys for confirming and selecting options
+ printer := pterm.DefaultInteractiveMultiselect.
+ WithOptions(options).
+ WithFilter(false).
+ WithKeyConfirm(keys.Enter).
+ WithKeySelect(keys.Space)
+
+ // Show the interactive multiselect and get the selected options
+ selectedOptions, _ := printer.Show()
+
+ // Print the selected options
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
```
-### header-custom/demo
+### interactive_select/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header-custom/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_select/demo/animation.svg)
@@ -1005,38 +2341,40 @@ func main() {
```go
package main
-import "github.com/pterm/pterm"
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
func main() {
- // All available options: https://pkg.go.dev/github.com/pterm/pterm#HeaderPrinter
+ // Initialize an empty slice to hold the options
+ var options []string
- // Build on top of DefaultHeader
- pterm.DefaultHeader. // Use DefaultHeader as base
- WithMargin(15).
- WithBackgroundStyle(pterm.NewStyle(pterm.BgCyan)).
- WithTextStyle(pterm.NewStyle(pterm.FgBlack)).
- Println("This is a custom header!")
- // Instead of printing the header you can set it to a variable.
- // You can then reuse your custom header.
+ // Generate 100 options and add them to the options slice
+ for i := 0; i < 100; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
- // Making a completely new HeaderPrinter
- newHeader := pterm.HeaderPrinter{
- TextStyle: pterm.NewStyle(pterm.FgBlack),
- BackgroundStyle: pterm.NewStyle(pterm.BgRed),
- Margin: 20,
+ // Generate 5 additional options with a specific message and add them to the options slice
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
}
- // Print header.
- newHeader.Println("This is a custom header!")
+ // Use PTerm's interactive select feature to present the options to the user and capture their selection
+ // The Show() method displays the options and waits for the user's input
+ selectedOption, _ := pterm.DefaultInteractiveSelect.WithOptions(options).Show()
+
+ // Display the selected option to the user with a green color for emphasis
+ pterm.Info.Printfln("Selected option: %s", pterm.Green(selectedOption))
}
```
-### interactive_confirm/demo
+### interactive_textinput/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_confirm/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/demo/animation.svg)
@@ -1050,25 +2388,26 @@ import (
)
func main() {
- result, _ := pterm.DefaultInteractiveConfirm.Show()
- pterm.Println() // Blank line
- pterm.Info.Printfln("You answered: %s", boolToText(result))
-}
+ // Create an interactive text input with single line input mode
+ textInput := pterm.DefaultInteractiveTextInput.WithMultiLine(false)
-func boolToText(b bool) string {
- if b {
- return pterm.Green("Yes")
- }
- return pterm.Red("No")
+ // Show the text input and get the result
+ result, _ := textInput.Show()
+
+ // Print a blank line for better readability
+ pterm.Println()
+
+ // Print the user's answer with an info prefix
+ pterm.Info.Printfln("You answered: %s", result)
}
```
-### interactive_continue/demo
+### interactive_textinput/multi-line
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_continue/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/multi-line/animation.svg)
@@ -1082,8 +2421,19 @@ import (
)
func main() {
- result, _ := pterm.DefaultInteractiveContinue.Show()
- pterm.Println() // Blank line
+ // Create a default interactive text input with multi-line enabled.
+ // This allows the user to input multiple lines of text.
+ textInput := pterm.DefaultInteractiveTextInput.WithMultiLine()
+
+ // Show the text input to the user and store the result.
+ // The second return value (an error) is ignored with '_'.
+ result, _ := textInput.Show()
+
+ // Print a blank line for better readability in the output.
+ pterm.Println()
+
+ // Print the user's input prefixed with an informational message.
+ // The '%s' placeholder is replaced with the user's input.
pterm.Info.Printfln("You answered: %s", result)
}
@@ -1091,9 +2441,9 @@ func main() {
-### interactive_multiselect/custom-checkmarks
+### interactive_textinput/password
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-checkmarks/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/password/animation.svg)
@@ -1102,37 +2452,148 @@ func main() {
```go
package main
-import (
- "fmt"
+import "github.com/pterm/pterm"
- "atomicgo.dev/keyboard/keys"
+func main() {
+ // Create an interactive text input with a mask for password input
+ passwordInput := pterm.DefaultInteractiveTextInput.WithMask("*")
+
+ // Show the password input prompt and store the result
+ result, _ := passwordInput.Show("Enter your password")
+
+ // Get the default logger from PTerm
+ logger := pterm.DefaultLogger
+
+ // Log the received password (masked)
+ // Note: In a real-world application, you should never log passwords
+ logger.Info("Password received", logger.Args("password", result))
+}
+
+```
+
+
+
+### logger/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/demo/animation.svg)
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
"github.com/pterm/pterm"
+ "time"
)
-func main() {
- var options []string
+func main() {
+ // Create a logger with trace level
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
+
+ // Log a trace level message
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Define a map with interesting stuff
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+
+ // Log a debug level message with arguments from the map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an info level message
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log a warning level message
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an error level message
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an info level message with a long text that will be automatically wrapped
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log a fatal level message
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
+}
+
+// Function to pause the execution for 3 seconds
+func sleep() {
+ time.Sleep(time.Second * 3)
+}
+
+```
+
+
+
+### logger/custom-key-styles
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/custom-key-styles/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a logger with a level of Trace or higher.
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
+
+ // Define a new style for the "priority" key.
+ priorityStyle := map[string]pterm.Style{
+ "priority": *pterm.NewStyle(pterm.FgRed),
+ }
+
+ // Overwrite all key styles with the new map.
+ logger = logger.WithKeyStyles(priorityStyle)
+
+ // Log an info message. The "priority" key will be displayed in red.
+ logger.Info("The priority key should now be red", logger.Args("priority", "low", "foo", "bar"))
+
+ // Define a new style for the "foo" key.
+ fooStyle := *pterm.NewStyle(pterm.FgBlue)
- for i := 0; i < 5; i++ {
- options = append(options, fmt.Sprintf("Option %d", i))
- }
+ // Append the new style to the existing ones.
+ logger.AppendKeyStyle("foo", fooStyle)
- printer := pterm.DefaultInteractiveMultiselect.WithOptions(options)
- printer.Filter = false
- printer.KeyConfirm = keys.Enter
- printer.KeySelect = keys.Space
- printer.Checkmark = &pterm.Checkmark{Checked: pterm.Green("+"), Unchecked: pterm.Red("-")}
- selectedOptions, _ := printer.Show()
- pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+ // Log another info message. The "foo" key will be displayed in blue.
+ logger.Info("The foo key should now be blue", logger.Args("priority", "low", "foo", "bar"))
}
```
-### interactive_multiselect/custom-keys
+### logger/default
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-keys/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/default/animation.svg)
@@ -1142,34 +2603,53 @@ func main() {
package main
import (
- "fmt"
-
- "atomicgo.dev/keyboard/keys"
"github.com/pterm/pterm"
+ "time"
)
func main() {
- var options []string
+ // Create a logger with a level of Trace or higher.
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
- for i := 0; i < 5; i++ {
- options = append(options, fmt.Sprintf("Option %d", i))
+ // Log a trace message with additional arguments.
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Create a map of interesting stuff.
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
}
- printer := pterm.DefaultInteractiveMultiselect.WithOptions(options)
- printer.Filter = false
- printer.KeyConfirm = keys.Enter
- printer.KeySelect = keys.Space
- selectedOptions, _ := printer.Show()
- pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+ // Log a debug message with arguments from a map.
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+
+ // Log an info message with additional arguments.
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Log a warning message with additional arguments.
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Log an error message with additional arguments.
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Log an info message with additional arguments. PTerm will automatically wrap long logs.
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Pause for 2 seconds.
+ time.Sleep(time.Second * 2)
+
+ // Log a fatal message with additional arguments. This will terminate the process.
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
```
-### interactive_multiselect/demo
+### logger/json
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/json/animation.svg)
@@ -1178,34 +2658,40 @@ func main() {
```go
package main
-import (
- "fmt"
-
- "github.com/pterm/pterm"
-)
+import "github.com/pterm/pterm"
func main() {
- var options []string
+ // Create a logger with Trace level and JSON formatter
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithFormatter(pterm.LogFormatterJSON)
- for i := 0; i < 100; i++ {
- options = append(options, fmt.Sprintf("Option %d", i))
- }
+ // Log a Trace level message with additional arguments
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
- for i := 0; i < 5; i++ {
- options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
+ // Create a map of interesting stuff
+ interestingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
}
- selectedOptions, _ := pterm.DefaultInteractiveMultiselect.WithOptions(options).Show()
- pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+ // Log a Debug level message with arguments from the map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
+
+ // Log Info, Warn, Error, and Fatal level messages with additional arguments
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
```
-### interactive_select/demo
+### logger/with-caller
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_select/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/with-caller/animation.svg)
@@ -1214,34 +2700,48 @@ func main() {
```go
package main
-import (
- "fmt"
-
- "github.com/pterm/pterm"
-)
+import "github.com/pterm/pterm"
func main() {
- var options []string
+ // Create a logger with Trace level and caller information
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithCaller()
- for i := 0; i < 100; i++ {
- options = append(options, fmt.Sprintf("Option %d", i))
- }
+ // Log a trace message with additional arguments
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
- for i := 0; i < 5; i++ {
- options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
+ // Create a map of interesting stuff
+ interestingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
}
- selectedOption, _ := pterm.DefaultInteractiveSelect.WithOptions(options).Show()
- pterm.Info.Printfln("Selected option: %s", pterm.Green(selectedOption))
+ // Log a debug message with arguments from a map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
+
+ // Log an info message with additional arguments
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Log a warning message with additional arguments
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Log an error message with additional arguments
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Log an info message with additional arguments. PTerm will automatically wrap long logs.
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Log a fatal message with additional arguments. This will terminate the process.
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
```
-### interactive_textinput/demo
+### multiple-live-printers/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/multiple-live-printers/demo/animation.svg)
@@ -1251,38 +2751,62 @@ func main() {
package main
import (
+ "time"
+
"github.com/pterm/pterm"
)
func main() {
- result, _ := pterm.DefaultInteractiveTextInput.WithMultiLine(false).Show()
- pterm.Println() // Blank line
- pterm.Info.Printfln("You answered: %s", result)
-}
+ // Create a multi printer for managing multiple printers
+ multi := pterm.DefaultMultiPrinter
-```
+ // Create two spinners with their own writers
+ spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
+ spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
-
+ // Create five progress bars with their own writers and a total of 100
+ pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
+ pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
+ pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
+ pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
+ pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
-### interactive_textinput/multi-line
+ // Start the multi printer
+ multi.Start()
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/multi-line/animation.svg)
+ // Increment progress bars and spinners based on certain conditions
+ for i := 1; i <= 100; i++ {
+ pb1.Increment() // Increment progress bar 1 every iteration
-
+ if i%2 == 0 {
+ pb2.Add(3) // Add 3 to progress bar 2 every even iteration
+ }
-SHOW SOURCE
+ if i%5 == 0 {
+ pb3.Increment() // Increment progress bar 3 every 5th iteration
+ }
-```go
-package main
+ if i%10 == 0 {
+ pb4.Increment() // Increment progress bar 4 every 10th iteration
+ }
-import (
- "github.com/pterm/pterm"
-)
+ if i%3 == 0 {
+ pb5.Increment() // Increment progress bar 5 every 3rd iteration
+ }
-func main() {
- result, _ := pterm.DefaultInteractiveTextInput.WithMultiLine().Show() // Text input with multi line enabled
- pterm.Println() // Blank line
- pterm.Info.Printfln("You answered: %s", result)
+ if i%50 == 0 {
+ spinner1.Success("Spinner 1 is done!") // Mark spinner 1 as successful every 50th iteration
+ }
+
+ if i%60 == 0 {
+ spinner2.Fail("Spinner 2 failed!") // Mark spinner 2 as failed every 60th iteration
+ }
+
+ time.Sleep(time.Millisecond * 50) // Sleep for 50 milliseconds between each iteration
+ }
+
+ // Stop the multi printer
+ multi.Stop()
}
```
@@ -1303,13 +2827,20 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Declare panels in a two dimensional grid system.
+ // Define panels in a 2D grid system
panels := pterm.Panels{
- {{Data: "This is the first panel"}, {Data: pterm.DefaultHeader.Sprint("Hello, World!")}, {Data: "This\npanel\ncontains\nmultiple\nlines"}},
- {{Data: pterm.Red("This is another\npanel line")}, {Data: "This is the second panel\nwith a new line"}},
+ {
+ {Data: "This is the first panel"},
+ {Data: pterm.DefaultHeader.Sprint("Hello, World!")},
+ {Data: "This\npanel\ncontains\nmultiple\nlines"},
+ },
+ {
+ {Data: pterm.Red("This is another\npanel line")},
+ {Data: "This is the second panel\nwith a new line"},
+ },
}
- // Print panels.
+ // Render the panels with a padding of 5
_ = pterm.DefaultPanel.WithPanels(panels).WithPadding(5).Render()
}
@@ -1317,9 +2848,9 @@ func main() {
-### paragraph/customized
+### paragraph/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/customized/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/demo/animation.svg)
@@ -1331,15 +2862,18 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print a paragraph with a custom maximal width.
- pterm.DefaultParagraph.WithMaxWidth(60).Println("This is a custom paragraph printer. As you can see, no words are separated, " +
+ // Using the default paragraph printer to print a long text.
+ // The text is split at the spaces, which is useful for continuous text of all kinds.
+ // The line width can be manually adjusted if needed.
+ pterm.DefaultParagraph.Println("This is the default paragraph printer. As you can see, no words are separated, " +
"but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
- // Print one line space.
+ // Printing a line space for separation.
pterm.Println()
- // Print text without a paragraph printer.
+ // Printing a long text without using the paragraph printer.
+ // The default Println() function is used here, which does not provide intelligent splitting.
pterm.Println("This text is written with the default Println() function. No intelligent splitting here." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
}
@@ -1348,9 +2882,9 @@ func main() {
-### paragraph/demo
+### paragraph/customized
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/customized/animation.svg)
@@ -1362,17 +2896,23 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print long text with default paragraph printer.
- pterm.DefaultParagraph.Println("This is the default paragraph printer. As you can see, no words are separated, " +
+ // Define a long text to be printed as a paragraph.
+ longText := "This is a custom paragraph printer. As you can see, no words are separated, " +
"but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
- "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"
- // Print one line space.
+ // Print the long text as a paragraph with a custom maximal width of 60 characters.
+ pterm.DefaultParagraph.WithMaxWidth(60).Println(longText)
+
+ // Print a line space to separate the paragraph from the following text.
pterm.Println()
- // Print long text without paragraph printer.
- pterm.Println("This text is written with the default Println() function. No intelligent splitting here." +
- "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+ // Define another long text to be printed without a paragraph printer.
+ longTextWithoutParagraph := "This text is written with the default Println() function. No intelligent splitting here." +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"
+
+ // Print the long text without using a paragraph printer.
+ pterm.Println(longTextWithoutParagraph)
}
```
@@ -1393,17 +2933,31 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Enable debug messages.
+ // Enable debug messages in PTerm.
pterm.EnableDebugMessages()
- pterm.Debug.Println("Hello, World!") // Print Debug.
- pterm.Info.Println("Hello, World!") // Print Info.
- pterm.Success.Println("Hello, World!") // Print Success.
- pterm.Warning.Println("Hello, World!") // Print Warning.
- pterm.Error.Println("Errors show the filename and linenumber inside the terminal!") // Print Error.
- pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!") // Print Error.
+ // Print a debug message with PTerm.
+ pterm.Debug.Println("Hello, World!")
+
+ // Print an informational message with PTerm.
+ pterm.Info.Println("Hello, World!")
+
+ // Print a success message with PTerm.
+ pterm.Success.Println("Hello, World!")
+
+ // Print a warning message with PTerm.
+ pterm.Warning.Println("Hello, World!")
+
+ // Print an error message with PTerm. This will also display the filename and line number in the terminal.
+ pterm.Error.Println("Errors show the filename and linenumber inside the terminal!")
+
+ // Print an informational message with PTerm, with line number.
+ // This demonstrates that other PrefixPrinters can also display line numbers.
+ pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!")
+
// Temporarily set Fatal to false, so that the CI won't crash.
- pterm.Fatal.WithFatal(false).Println("Hello, World!") // Print Fatal.
+ // This will print a fatal message with PTerm, but won't terminate the program.
+ pterm.Fatal.WithFatal(false).Println("Hello, World!")
}
```
@@ -1428,20 +2982,96 @@ import (
"github.com/pterm/pterm"
)
-// Slice of strings with placeholder text.
+// Slice of strings representing names of pseudo applications to be downloaded.
var fakeInstallList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
"pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
func main() {
- // Create progressbar as fork from the default progressbar.
+ // Create a progressbar with the total steps equal to the number of items in fakeInstallList.
+ // Set the initial title of the progressbar to "Downloading stuff".
p, _ := pterm.DefaultProgressbar.WithTotal(len(fakeInstallList)).WithTitle("Downloading stuff").Start()
+ // Loop over each item in the fakeInstallList.
for i := 0; i < p.Total; i++ {
- p.UpdateTitle("Downloading " + fakeInstallList[i]) // Update the title of the progressbar.
- pterm.Success.Println("Downloading " + fakeInstallList[i]) // If a progressbar is running, each print will be printed above the progressbar.
- p.Increment() // Increment the progressbar by one. Use Add(x int) to increment by a custom amount.
- time.Sleep(time.Millisecond * 350) // Sleep 350 milliseconds.
+ // Simulate a slow download for the 7th item.
+ if i == 6 {
+ time.Sleep(time.Second * 3)
+ }
+
+ // Update the title of the progressbar with the current item being downloaded.
+ p.UpdateTitle("Downloading " + fakeInstallList[i])
+
+ // Print a success message for the current download. This will be printed above the progressbar.
+ pterm.Success.Println("Downloading " + fakeInstallList[i])
+
+ // Increment the progressbar by one to indicate progress.
+ p.Increment()
+
+ // Pause for 350 milliseconds to simulate the time taken for each download.
+ time.Sleep(time.Millisecond * 350)
+ }
+}
+
+```
+
+
+
+### progressbar/multiple
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/progressbar/multiple/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a multi printer instance from the default one
+ multi := pterm.DefaultMultiPrinter
+
+ // Create five progress bars with a total of 100 units each, and assign each a new writer from the multi printer
+ pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
+ pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
+ pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
+ pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
+ pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
+
+ // Start the multi printer
+ multi.Start()
+
+ // Loop to increment progress bars based on certain conditions
+ for i := 1; i <= 100; i++ {
+ pb1.Increment() // Increment the first progress bar at each iteration
+
+ if i%2 == 0 {
+ pb2.Add(3) // Add 3 units to the second progress bar at every even iteration
+ }
+
+ if i%5 == 0 {
+ pb3.Increment() // Increment the third progress bar at every fifth iteration
+ }
+
+ if i%10 == 0 {
+ pb4.Increment() // Increment the fourth progress bar at every tenth iteration
+ }
+
+ if i%3 == 0 {
+ pb5.Increment() // Increment the fifth progress bar at every third iteration
+ }
+
+ time.Sleep(time.Millisecond * 50) // Pause for 50 milliseconds at each iteration
}
+
+ // Stop the multi printer
+ multi.Stop()
}
```
@@ -1462,14 +3092,16 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Print a section with level one.
+ // Create a section with level one and print it.
pterm.DefaultSection.Println("This is a section!")
- // Print placeholder.
+
+ // Print an informational message.
pterm.Info.Println("And here is some text.\nThis text could be anything.\nBasically it's just a placeholder")
- // Print a section with level two.
+ // Create a section with level two and print it.
pterm.DefaultSection.WithLevel(2).Println("This is another section!")
- // Print placeholder.
+
+ // Print another informational message.
pterm.Info.Println("And this is\nmore placeholder text")
}
@@ -1477,6 +3109,53 @@ func main() {
+### slog/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/slog/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "log/slog"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a new slog handler with the default PTerm logger
+ handler := pterm.NewSlogHandler(&pterm.DefaultLogger)
+
+ // Create a new slog logger with the handler
+ logger := slog.New(handler)
+
+ // Log a debug message (won't show by default)
+ logger.Debug("This is a debug message that won't show")
+
+ // Change the log level to debug to enable debug messages
+ pterm.DefaultLogger.Level = pterm.LogLevelDebug
+
+ // Log a debug message (will show because debug level is enabled)
+ logger.Debug("This is a debug message", "changedLevel", true)
+
+ // Log an info message
+ logger.Info("This is an info message")
+
+ // Log a warning message
+ logger.Warn("This is a warning message")
+
+ // Log an error message
+ logger.Error("This is an error message")
+}
+
+```
+
+
+
### spinner/demo
![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/spinner/demo/animation.svg)
@@ -1542,6 +3221,68 @@ func main() {
+### spinner/multiple
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/spinner/multiple/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a multi printer. This allows multiple spinners to print simultaneously.
+ multi := pterm.DefaultMultiPrinter
+
+ // Create and start spinner 1 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 1".
+ spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
+
+ // Create and start spinner 2 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 2".
+ spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
+
+ // Create and start spinner 3 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 3".
+ spinner3, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 3")
+
+ // Start the multi printer. This will start printing all the spinners.
+ multi.Start()
+
+ // Wait for 1 second.
+ time.Sleep(time.Millisecond * 1000)
+
+ // Stop spinner 1 with a success message.
+ spinner1.Success("Spinner 1 is done!")
+
+ // Wait for 750 milliseconds.
+ time.Sleep(time.Millisecond * 750)
+
+ // Stop spinner 2 with a failure message.
+ spinner2.Fail("Spinner 2 failed!")
+
+ // Wait for 500 milliseconds.
+ time.Sleep(time.Millisecond * 500)
+
+ // Stop spinner 3 with a warning message.
+ spinner3.Warning("Spinner 3 has a warning!")
+
+ // Stop the multi printer. This will stop printing all the spinners.
+ multi.Stop()
+}
+
+```
+
+
+
### style/demo
![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/style/demo/animation.svg)
@@ -1556,12 +3297,16 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Create styles as new variables
+ // Define a primary style with light cyan foreground, gray background, and bold text
primary := pterm.NewStyle(pterm.FgLightCyan, pterm.BgGray, pterm.Bold)
+
+ // Define a secondary style with light green foreground, white background, and italic text
secondary := pterm.NewStyle(pterm.FgLightGreen, pterm.BgWhite, pterm.Italic)
- // Use created styles
+ // Print "Hello, World!" with the primary style
primary.Println("Hello, World!")
+
+ // Print "Hello, World!" with the secondary style
secondary.Println("Hello, World!")
}
@@ -1569,9 +3314,9 @@ func main() {
-### table/boxed
+### table/demo
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/boxed/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/demo/animation.svg)
@@ -1583,23 +3328,40 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Create a fork of the default table, fill it with data and print it.
- // Data can also be generated and inserted later.
- pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(pterm.TableData{
+ // Define the data for the first table
+ tableData1 := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
- {"Paul", "Dean", "nisi.dictum.augue@velitAliquam.co.uk", ""},
- {"Callie", "Mckay", "egestas.nunc.sed@est.com", "这是一个测试, haha!"},
- {"Libby", "Camacho", "aliquet.lobortis@semper.com", "just a test, hey!"},
- }).Render()
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with a header and the defined data, then render it
+ pterm.DefaultTable.WithHasHeader().WithData(tableData1).Render()
+
+ pterm.Println() // Blank line
+
+ // Define the data for the second table
+ tableData2 := pterm.TableData{
+ {"Firstname", "Lastname", "Email"},
+ {"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
+ {"Libby", "Camacho", "lobortis@semper.com"},
+ {"张", "小宝", "zhang@example.com"},
+ }
+
+ // Create another table with a header and the defined data, then render it
+ pterm.DefaultTable.WithHasHeader().WithData(tableData2).Render()
}
```
-### table/demo
+### table/boxed
-![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/demo/animation.svg)
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/boxed/animation.svg)
@@ -1611,25 +3373,21 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Create a fork of the default table, fill it with data and print it.
- // Data can also be generated and inserted later.
- pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{
+ // Define the data for the table.
+ // Each inner slice represents a row in the table.
+ // The first row is considered as the header of the table.
+ tableData := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
- {"Paul", "Dean", "nisi.dictum.augue@velitAliquam.co.uk", ""},
- {"Callie", "Mckay", "egestas.nunc.sed@est.com", "这是一个测试, haha!"},
- {"Libby", "Camacho", "aliquet.lobortis@semper.com", "just a test, hey!"},
- }).Render()
-
- pterm.Println() // Blank line
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
- // Create a table with multiple lines in a row.
- pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{
- {"Firstname", "Lastname", "Email"},
- {"Paul\n\nNewline", "Dean", "nisi.dictum.augue@velitAliquam.co.uk"},
- {"Callie", "Mckay", "egestas.nunc.sed@est.com\nNewline"},
- {"Libby", "Camacho", "aliquet.lobortis@semper.com"},
- {"张", "小宝", "zhang@example.com"},
- }).Render()
+ // Create a table with the defined data.
+ // The table has a header and is boxed.
+ // Finally, render the table to print it.
+ pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
}
```
@@ -1650,14 +3408,19 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Create a table with multiple lines in a row and set a row separator.
- pterm.DefaultTable.WithHasHeader().WithRowSeparator("-").WithHeaderRowSeparator("-").WithData(pterm.TableData{
+ // Define the data for the table.
+ data := pterm.TableData{
{"Firstname", "Lastname", "Email"},
- {"Paul\n\nNewline", "Dean", "nisi.dictum.augue@velitAliquam.co.uk"},
- {"Callie", "Mckay", "egestas.nunc.sed@est.com\nNewline"},
- {"Libby", "Camacho", "aliquet.lobortis@semper.com"},
+ {"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
+ {"Libby", "Camacho", "lobortis@semper.com"},
{"张", "小宝", "zhang@example.com"},
- }).Render()
+ }
+
+ // Create and render the table.
+ // The options are chained in a single line for simplicity.
+ // The table has a header, a row separator, and a header row separator.
+ pterm.DefaultTable.WithHasHeader().WithRowSeparator("-").WithHeaderRowSeparator("-").WithData(data).Render()
}
```
@@ -1678,14 +3441,21 @@ package main
import "github.com/pterm/pterm"
func main() {
- // Create a fork of the default table, fill it with data and print it.
- // Data can also be generated and inserted later.
- pterm.DefaultTable.WithHasHeader().WithRightAlignment().WithData(pterm.TableData{
+ // Define the data for the table.
+ // Each inner slice represents a row in the table.
+ // The first row is considered as the header.
+ tableData := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
- {"Paul", "Dean", "nisi.dictum.augue@velitAliquam.co.uk", ""},
- {"Callie", "Mckay", "egestas.nunc.sed@est.com", "这是一个测试, haha!"},
- {"Libby", "Camacho", "aliquet.lobortis@semper.com", "just a test, hey!"},
- }).Render()
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with the defined data.
+ // The table has a header and the text in the cells is right-aligned.
+ // The Render() method is used to print the table to the console.
+ pterm.DefaultTable.WithHasHeader().WithRightAlignment().WithData(tableData).Render()
}
```
@@ -1710,23 +3480,27 @@ import (
)
func main() {
- // Print info.
- pterm.Info.Println("These are the default theme styles.\n" +
- "You can modify them easily to your personal preference,\n" +
- "or create new themes from scratch :)")
+ // Print an informational message about the default theme styles.
+ pterm.Info.Println("These are the default theme styles.\nYou can modify them easily to your personal preference,\nor create new themes from scratch :)")
- pterm.Println() // Print one line space.
+ // Print a blank line for better readability.
+ pterm.Println()
- // Print every value of the default theme with its own style.
+ // Get the value and type of the default theme.
v := reflect.ValueOf(pterm.ThemeDefault)
typeOfS := v.Type()
+ // Check if the type of the default theme is 'pterm.Theme'.
if typeOfS == reflect.TypeOf(pterm.Theme{}) {
+ // Iterate over each field in the default theme.
for i := 0; i < v.NumField(); i++ {
+ // Try to convert the field to 'pterm.Style'.
field, ok := v.Field(i).Interface().(pterm.Style)
if ok {
+ // Print the field name using its own style.
field.Println(typeOfS.Field(i).Name)
}
+ // Pause for a quarter of a second to make the output easier to read.
time.Sleep(time.Millisecond * 250)
}
}
@@ -1752,11 +3526,17 @@ import (
)
func main() {
+ // Define a tree structure using pterm.TreeNode
tree := pterm.TreeNode{
+ // The top node of the tree
Text: "Top node",
+ // The children of the top node
Children: []pterm.TreeNode{{
+ // A child node
Text: "Child node",
+ // The children of the child node
Children: []pterm.TreeNode{
+ // Grandchildren nodes
{Text: "Grandchild node"},
{Text: "Grandchild node"},
{Text: "Grandchild node"},
@@ -1764,6 +3544,7 @@ func main() {
}},
}
+ // Render the tree with the defined structure as the root
pterm.DefaultTree.WithRoot(tree).Render()
}
@@ -1788,37 +3569,37 @@ import (
)
func main() {
- // You can use a LeveledList here, for easy generation.
+ // Define a leveled list to represent the structure of the directories.
leveledList := pterm.LeveledList{
- pterm.LeveledListItem{Level: 0, Text: "C:"},
- pterm.LeveledListItem{Level: 1, Text: "Users"},
- pterm.LeveledListItem{Level: 1, Text: "Windows"},
- pterm.LeveledListItem{Level: 1, Text: "Programs"},
- pterm.LeveledListItem{Level: 1, Text: "Programs(x86)"},
- pterm.LeveledListItem{Level: 1, Text: "dev"},
- pterm.LeveledListItem{Level: 0, Text: "D:"},
- pterm.LeveledListItem{Level: 0, Text: "E:"},
- pterm.LeveledListItem{Level: 1, Text: "Movies"},
- pterm.LeveledListItem{Level: 1, Text: "Music"},
- pterm.LeveledListItem{Level: 2, Text: "LinkinPark"},
- pterm.LeveledListItem{Level: 1, Text: "Games"},
- pterm.LeveledListItem{Level: 2, Text: "Shooter"},
- pterm.LeveledListItem{Level: 3, Text: "CallOfDuty"},
- pterm.LeveledListItem{Level: 3, Text: "CS:GO"},
- pterm.LeveledListItem{Level: 3, Text: "Battlefield"},
- pterm.LeveledListItem{Level: 4, Text: "Battlefield 1"},
- pterm.LeveledListItem{Level: 4, Text: "Battlefield 2"},
- pterm.LeveledListItem{Level: 0, Text: "F:"},
- pterm.LeveledListItem{Level: 1, Text: "dev"},
- pterm.LeveledListItem{Level: 2, Text: "dops"},
- pterm.LeveledListItem{Level: 2, Text: "PTerm"},
- }
-
- // Generate tree from LeveledList.
+ {Level: 0, Text: "C:"},
+ {Level: 1, Text: "Users"},
+ {Level: 1, Text: "Windows"},
+ {Level: 1, Text: "Programs"},
+ {Level: 1, Text: "Programs(x86)"},
+ {Level: 1, Text: "dev"},
+ {Level: 0, Text: "D:"},
+ {Level: 0, Text: "E:"},
+ {Level: 1, Text: "Movies"},
+ {Level: 1, Text: "Music"},
+ {Level: 2, Text: "LinkinPark"},
+ {Level: 1, Text: "Games"},
+ {Level: 2, Text: "Shooter"},
+ {Level: 3, Text: "CallOfDuty"},
+ {Level: 3, Text: "CS:GO"},
+ {Level: 3, Text: "Battlefield"},
+ {Level: 4, Text: "Battlefield 1"},
+ {Level: 4, Text: "Battlefield 2"},
+ {Level: 0, Text: "F:"},
+ {Level: 1, Text: "dev"},
+ {Level: 2, Text: "dops"},
+ {Level: 2, Text: "PTerm"},
+ }
+
+ // Convert the leveled list into a tree structure.
root := putils.TreeFromLeveledList(leveledList)
- root.Text = "Computer"
+ root.Text = "Computer" // Set the root node text.
- // Render TreePrinter
+ // Render the tree structure using the default tree printer.
pterm.DefaultTree.WithRoot(root).Render()
}
diff --git a/vendor/github.com/pterm/pterm/SECURITY.md b/vendor/github.com/pterm/pterm/SECURITY.md
new file mode 100644
index 00000000..3e4653f8
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/SECURITY.md
@@ -0,0 +1,24 @@
+# PTerm Security Policy
+This security policy applies to the PTerm GitHub repository and outlines the process for reporting security issues and handling security incidents. The primary goal of this policy is to ensure the safety and integrity of the PTerm codebase and to minimize the impact of security incidents on our users.
+
+## 1. Overview
+PTerm is a command-line interface (CLI) tool library, and we believe the security risks associated with it are minimal. However, we recognize that vulnerabilities can still arise, and we are committed to addressing them promptly and transparently.
+
+## 2. Reporting Security Issues
+If you discover a security issue in PTerm, please follow these steps:
+
+Open a new issue in the PTerm GitHub repository, describing the security problem in detail.
+
+## 3. Vulnerable Dependencies
+If a dependency of PTerm is found to be vulnerable or infected and requires immediate updates, please follow these steps:
+
+1. Open a new issue in the PTerm GitHub repository, describing the vulnerable dependency and the need for an update.
+2. *Optional: Contact @MarvinJWendt directly via Twitter or Discord to alert them to the issue.*
+
+## 4. Incident Response
+Upon receiving a security report, the PTerm team will:
+
+1. Acknowledge receipt of the report and review the issue.
+2. Investigate the issue and determine the severity and impact.
+3. Develop and implement a fix or mitigation plan, as necessary.
+4. Update the PTerm repository and notify users, if applicable.
diff --git a/vendor/github.com/pterm/pterm/area_printer.go b/vendor/github.com/pterm/pterm/area_printer.go
index 5f3e5b04..ed4b0c22 100644
--- a/vendor/github.com/pterm/pterm/area_printer.go
+++ b/vendor/github.com/pterm/pterm/area_printer.go
@@ -1,6 +1,7 @@
package pterm
import (
+ "io"
"strings"
"atomicgo.dev/cursor"
@@ -47,6 +48,11 @@ func (p AreaPrinter) WithCenter(b ...bool) *AreaPrinter {
return &p
}
+// SetWriter sets the writer for the AreaPrinter.
+func (p *AreaPrinter) SetWriter(writer io.Writer) {
+
+}
+
// Update overwrites the content of the AreaPrinter.
// Can be used live.
func (p *AreaPrinter) Update(text ...interface{}) {
diff --git a/vendor/github.com/pterm/pterm/box_printer.go b/vendor/github.com/pterm/pterm/box_printer.go
index 8bff4671..3185e024 100644
--- a/vendor/github.com/pterm/pterm/box_printer.go
+++ b/vendor/github.com/pterm/pterm/box_printer.go
@@ -240,8 +240,8 @@ func (p BoxPrinter) Sprint(a ...interface{}) string {
maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
} else {
p.Title = strings.ReplaceAll(p.Title, "\n", " ")
- if (maxWidth + p.RightPadding + p.LeftPadding - 4) < len(RemoveColorFromString(p.Title)) {
- p.RightPadding = len(RemoveColorFromString(p.Title)) - (maxWidth + p.RightPadding + p.LeftPadding - 5)
+ if (maxWidth + p.RightPadding + p.LeftPadding - 4) < internal.GetStringMaxWidth(p.Title) {
+ p.RightPadding = internal.GetStringMaxWidth(p.Title) - (maxWidth + p.RightPadding + p.LeftPadding - 5)
}
if p.TitleTopLeft {
topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + internal.AddTitleToLine(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding, true) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
diff --git a/vendor/github.com/pterm/pterm/bulletlist_printer.go b/vendor/github.com/pterm/pterm/bulletlist_printer.go
index ed997aa5..8e6afcb0 100644
--- a/vendor/github.com/pterm/pterm/bulletlist_printer.go
+++ b/vendor/github.com/pterm/pterm/bulletlist_printer.go
@@ -116,10 +116,18 @@ func (l BulletListPrinter) Srender() (string, error) {
item.BulletStyle = l.BulletStyle
}
}
- if item.Bullet == "" {
- ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(l.Bullet) + " " + item.TextStyle.Sprint(item.Text) + "\n"
- } else {
- ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(item.Bullet) + " " + item.TextStyle.Sprint(item.Text) + "\n"
+
+ split := strings.Split(item.Text, "\n")
+ for i, line := range split {
+ if i == 0 {
+ if item.Bullet == "" {
+ ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(l.Bullet) + " " + item.TextStyle.Sprint(line) + "\n"
+ } else {
+ ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(item.Bullet) + " " + item.TextStyle.Sprint(line) + "\n"
+ }
+ } else {
+ ret += strings.Repeat(" ", item.Level) + strings.Repeat(" ", len(item.Bullet)) + " " + item.TextStyle.Sprint(line) + "\n"
+ }
}
}
return ret, nil
diff --git a/vendor/github.com/pterm/pterm/color.go b/vendor/github.com/pterm/pterm/color.go
index 5f7eeef3..89ad025b 100644
--- a/vendor/github.com/pterm/pterm/color.go
+++ b/vendor/github.com/pterm/pterm/color.go
@@ -276,6 +276,23 @@ func (s Style) Add(styles ...Style) Style {
return ret
}
+// RemoveColor removes the given colors from the Style.
+func (s Style) RemoveColor(colors ...Color) Style {
+ ret := s
+
+ for _, c := range colors {
+ // remove via index
+ for i := 0; i < len(ret); i++ {
+ if ret[i] == c {
+ ret = append(ret[:i], ret[i+1:]...)
+ i--
+ }
+ }
+ }
+
+ return ret
+}
+
// Sprint formats using the default formats for its operands and returns the resulting string.
// Spaces are added between operands when neither is a string.
// Input will be colored with the parent Style.
diff --git a/vendor/github.com/pterm/pterm/heatmap_printer.go b/vendor/github.com/pterm/pterm/heatmap_printer.go
new file mode 100644
index 00000000..4fac71e3
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/heatmap_printer.go
@@ -0,0 +1,744 @@
+package pterm
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "math"
+ "strings"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultHeatmap contains standards, which can be used to print a HeatmapPrinter.
+var DefaultHeatmap = HeatmapPrinter{
+ AxisStyle: &ThemeDefault.HeatmapHeaderStyle,
+ SeparatorStyle: &ThemeDefault.HeatmapSeparatorStyle,
+ VerticalSeparator: "│",
+ TopRightCornerSeparator: "└",
+ TopLeftCornerSeparator: "┘",
+ BottomLeftCornerSeparator: "┐",
+ BottomRightCornerSeparator: "┌",
+ HorizontalSeparator: "─",
+ TSeparator: "┬",
+ TReverseSeparator: "┴",
+ LSeparator: "├",
+ LReverseSeparator: "┤",
+ TCrossSeparator: "┼",
+ LegendLabel: "Legend",
+ Boxed: true,
+ Grid: true,
+ Legend: true,
+ TextRGB: RGB{0, 0, 0, false},
+ RGBRange: []RGB{{R: 255, G: 0, B: 0, Background: true}, {R: 255, G: 165, B: 0, Background: true}, {R: 0, G: 255, B: 0, Background: true}},
+ TextColor: FgBlack,
+ Colors: []Color{BgRed, BgLightRed, BgYellow, BgLightYellow, BgLightGreen, BgGreen},
+
+ EnableRGB: false,
+}
+
+// HeatmapData is the type that contains the data of a HeatmapPrinter.
+type HeatmapData [][]float32
+
+type HeatmapAxis struct {
+ XAxis []string
+ YAxis []string
+}
+
+// HeatmapPrinter is able to render tables.
+type HeatmapPrinter struct {
+ HasHeader bool
+ AxisStyle *Style
+ VerticalSeparator string
+ TopRightCornerSeparator string
+ TopLeftCornerSeparator string
+ BottomLeftCornerSeparator string
+ BottomRightCornerSeparator string
+ HorizontalSeparator string
+ TSeparator string
+ TReverseSeparator string
+ LSeparator string
+ LReverseSeparator string
+ TCrossSeparator string
+ LegendLabel string
+ SeparatorStyle *Style
+ Data HeatmapData
+ Axis HeatmapAxis
+ Boxed bool
+ Grid bool
+ OnlyColoredCells bool
+ LegendOnlyColoredCells bool
+ EnableComplementaryColor bool
+ Legend bool
+ CellSize int
+ Colors []Color
+ TextColor Color
+ EnableRGB bool
+ RGBRange []RGB
+ TextRGB RGB
+ Writer io.Writer
+
+ minValue float32
+ maxValue float32
+
+ rgbLegendValue int
+}
+
+var complementaryColors = map[Color]Color{
+ BgBlack: FgLightWhite,
+ BgRed: FgCyan,
+ BgGreen: FgMagenta,
+ BgYellow: FgBlue,
+ BgBlue: FgYellow,
+ BgMagenta: FgGreen,
+ BgCyan: FgRed,
+ BgWhite: FgBlack,
+ BgDefault: FgBlack,
+ BgDarkGray: FgLightWhite,
+ BgLightRed: FgLightCyan,
+ BgLightGreen: FgLightMagenta,
+ BgLightYellow: FgLightBlue,
+ BgLightBlue: FgLightYellow,
+ BgLightMagenta: FgLightGreen,
+ BgLightCyan: FgLightRed,
+ BgLightWhite: FgBlack,
+}
+
+// WithAxisData returns a new HeatmapPrinter, where the first line and row are headers.
+func (p HeatmapPrinter) WithAxisData(hd HeatmapAxis) *HeatmapPrinter {
+ p.HasHeader = true
+ p.Axis = hd
+ return &p
+}
+
+// WithAxisStyle returns a new HeatmapPrinter with a specific AxisStyle.
+func (p HeatmapPrinter) WithAxisStyle(style *Style) *HeatmapPrinter {
+ p.AxisStyle = style
+ return &p
+}
+
+// WithSeparatorStyle returns a new HeatmapPrinter with a specific SeparatorStyle.
+func (p HeatmapPrinter) WithSeparatorStyle(style *Style) *HeatmapPrinter {
+ p.SeparatorStyle = style
+ return &p
+}
+
+// WithData returns a new HeatmapPrinter with specific Data.
+func (p HeatmapPrinter) WithData(data [][]float32) *HeatmapPrinter {
+ p.Data = data
+ return &p
+}
+
+// WithTextColor returns a new HeatmapPrinter with a specific TextColor.
+// This sets EnableComplementaryColor to false.
+func (p HeatmapPrinter) WithTextColor(color Color) *HeatmapPrinter {
+ p.TextColor = color
+ p.EnableComplementaryColor = false
+ return &p
+}
+
+// WithTextRGB returns a new HeatmapPrinter with a specific TextRGB.
+// This sets EnableComplementaryColor to false.
+func (p HeatmapPrinter) WithTextRGB(rgb RGB) *HeatmapPrinter {
+ p.TextRGB = rgb
+ p.EnableComplementaryColor = false
+ return &p
+}
+
+// WithBoxed returns a new HeatmapPrinter with a box around the table.
+// If set to true, Grid will be set to true too.
+func (p HeatmapPrinter) WithBoxed(b ...bool) *HeatmapPrinter {
+ p.Boxed = internal.WithBoolean(b)
+ if p.Boxed && !p.Grid {
+ p.Grid = true
+ }
+ return &p
+}
+
+// WithGrid returns a new HeatmapPrinter with a grid.
+// If set to false, Boxed will be set to false too.
+func (p HeatmapPrinter) WithGrid(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.Grid = b2
+ if !b2 && p.Boxed {
+ p.Boxed = false
+ }
+ return &p
+}
+
+// WithEnableRGB returns a new HeatmapPrinter with RGB colors.
+func (p HeatmapPrinter) WithEnableRGB(b ...bool) *HeatmapPrinter {
+ p.EnableRGB = internal.WithBoolean(b)
+ return &p
+}
+
+// WithOnlyColoredCells returns a new HeatmapPrinter with only colored cells.
+func (p HeatmapPrinter) WithOnlyColoredCells(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.OnlyColoredCells = b2
+ return &p
+}
+
+// WithLegendOnlyColoredCells returns a new HeatmapPrinter with legend with only colored cells.
+// This sets the Legend to true.
+func (p HeatmapPrinter) WithLegendOnlyColoredCells(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.LegendOnlyColoredCells = b2
+ if b2 {
+ p.Legend = true
+ }
+ return &p
+}
+
+// WithEnableComplementaryColor returns a new HeatmapPrinter with complement color.
+func (p HeatmapPrinter) WithEnableComplementaryColor(b ...bool) *HeatmapPrinter {
+ p.EnableComplementaryColor = internal.WithBoolean(b)
+ return &p
+}
+
+// WithLegend returns a new HeatmapPrinter with a legend.
+func (p HeatmapPrinter) WithLegend(b ...bool) *HeatmapPrinter {
+ p.Legend = internal.WithBoolean(b)
+ return &p
+}
+
+// WithCellSize returns a new HeatmapPrinter with a specific cell size.
+// This only works if there is no header and OnlyColoredCells == true!
+func (p HeatmapPrinter) WithCellSize(i int) *HeatmapPrinter {
+ p.CellSize = i
+ return &p
+}
+
+// WithLegendLabel returns a new HeatmapPrinter with a specific legend tag.
+// This sets the Legend to true.
+func (p HeatmapPrinter) WithLegendLabel(s string) *HeatmapPrinter {
+ p.LegendLabel = s
+ p.Legend = true
+ return &p
+}
+
+// WithRGBRange returns a new HeatmapPrinter with a specific RGBRange.
+func (p HeatmapPrinter) WithRGBRange(rgb ...RGB) *HeatmapPrinter {
+ p.RGBRange = rgb
+ return &p
+}
+
+// WithColors returns a new HeatmapPrinter with a specific Colors.
+func (p HeatmapPrinter) WithColors(colors ...Color) *HeatmapPrinter {
+ p.Colors = colors
+ return &p
+}
+
+// WithWriter sets the Writer.
+func (p HeatmapPrinter) WithWriter(writer io.Writer) *HeatmapPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// Srender renders the HeatmapPrinter as a string.
+func (p HeatmapPrinter) Srender() (string, error) {
+ if err := p.errCheck(); err != nil {
+ return "", err
+ }
+
+ if p.SeparatorStyle == nil {
+ p.SeparatorStyle = DefaultHeatmap.SeparatorStyle
+ }
+ if p.AxisStyle == nil {
+ p.AxisStyle = DefaultHeatmap.AxisStyle
+ }
+
+ if RawOutput {
+ p.Legend = false
+ }
+
+ buffer := bytes.NewBufferString("")
+ xAmount := len(p.Data[0]) - 1
+ yAmount := len(p.Data) - 1
+ p.minValue, p.maxValue = minMaxFloat32(p.Data)
+
+ var data string
+ for _, datum := range p.Data {
+ for _, f := range datum {
+ data += Sprintf("%v\n", f)
+ }
+ }
+
+ if p.HasHeader {
+ data, xAmount, yAmount = p.computeAxisData(data, xAmount, yAmount)
+ }
+
+ colWidth := internal.GetStringMaxWidth(data)
+ legendColWidth := colWidth + 2
+
+ if p.OnlyColoredCells && (p.CellSize > colWidth || !p.HasHeader) {
+ colWidth = p.CellSize
+ }
+
+ if p.Boxed {
+ p.renderSeparatorRow(buffer, colWidth, xAmount, true)
+ }
+
+ p.renderData(buffer, colWidth, xAmount, yAmount)
+
+ if p.HasHeader {
+ p.renderHeader(buffer, colWidth, xAmount)
+ }
+
+ if p.Boxed {
+ p.renderSeparatorRow(buffer, colWidth, xAmount, false)
+ }
+
+ if p.Legend {
+ p.renderLegend(buffer, legendColWidth)
+ }
+
+ buffer.WriteString("\n")
+
+ return buffer.String(), nil
+}
+
+func (p HeatmapPrinter) computeAxisData(data string, xAmount, yAmount int) (string, int, int) {
+ var header string
+ for _, h := range p.Axis.XAxis {
+ header += h + "\n"
+ }
+ for _, h := range p.Axis.YAxis {
+ header += h + "\n"
+ }
+
+ if p.OnlyColoredCells {
+ data = header
+ } else {
+ data += header
+ }
+ xAmount++
+ yAmount++
+
+ p.Axis.YAxis = append(p.Axis.YAxis, "")
+
+ return data, xAmount, yAmount
+}
+
+func (p HeatmapPrinter) renderSeparatorRow(buffer *bytes.Buffer, colWidth, xAmount int, top bool) {
+ tSep := p.TReverseSeparator
+ rightSep := p.TopRightCornerSeparator
+ leftSep := p.TopLeftCornerSeparator
+
+ if top {
+ tSep = p.TSeparator
+ rightSep = p.BottomRightCornerSeparator
+ leftSep = p.BottomLeftCornerSeparator
+ } else {
+ buffer.WriteString("\n")
+ }
+ buffer.WriteString(p.SeparatorStyle.Sprint(rightSep))
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(tSep))
+ }
+ }
+ buffer.WriteString(p.SeparatorStyle.Sprint(leftSep))
+
+ if top {
+ buffer.WriteString("\n")
+ }
+}
+
+func (p HeatmapPrinter) renderLegend(buffer *bytes.Buffer, legendColWidth int) {
+ buffer.WriteString("\n")
+ buffer.WriteString("\n")
+ if p.Boxed {
+ p.boxLegend(buffer, p.LegendLabel, legendColWidth)
+ } else {
+ p.generateLegend(buffer, p.LegendLabel, legendColWidth)
+ }
+}
+
+func (p HeatmapPrinter) renderHeader(buffer *bytes.Buffer, colWidth int, xAmount int) {
+ buffer.WriteString("\n")
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LSeparator))
+ }
+ if p.Grid {
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TCrossSeparator))
+ }
+ }
+ }
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LReverseSeparator))
+ }
+ if p.Grid {
+ buffer.WriteString("\n")
+ }
+ for j, f := range p.Axis.XAxis {
+ if j == 0 {
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ ct := internal.CenterText(" ", colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ var ct string
+ ct = internal.CenterText(Sprintf("%v", f), colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+
+ if j < xAmount {
+ if !p.Boxed && j == xAmount-1 {
+ continue
+ }
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ }
+}
+
+func (p HeatmapPrinter) renderData(buffer *bytes.Buffer, colWidth int, xAmount int, yAmount int) {
+ for i, datum := range p.Data {
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ for j, f := range datum {
+ if j == 0 && p.HasHeader {
+ ct := internal.CenterText(p.Axis.YAxis[i], colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ var ct string
+ if p.OnlyColoredCells {
+ ct = internal.CenterText(" ", colWidth)
+ } else {
+ ct = internal.CenterText(Sprintf("%v", f), colWidth)
+ }
+ if len(ct) < colWidth {
+ if len(Sprintf("%v", f)) == 1 {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ } else {
+ ct = strings.Repeat(" ", colWidth-len(ct)) + ct
+ }
+ }
+ if p.EnableRGB {
+ rgb := p.RGBRange[0].Fade(p.minValue, p.maxValue, f, p.RGBRange[1:]...)
+ rgbStyle := NewRGBStyle(p.TextRGB, rgb)
+ if p.EnableComplementaryColor {
+ complimentary := NewRGB(internal.Complementary(rgb.R, rgb.G, rgb.B))
+ rgbStyle = NewRGBStyle(complimentary, rgb)
+ }
+ buffer.WriteString(rgbStyle.Sprint(ct))
+ } else {
+ color := getColor(p.minValue, p.maxValue, f, p.Colors...)
+ fgColor := p.TextColor
+ if p.EnableComplementaryColor {
+ fgColor = complementaryColors[color]
+ }
+ buffer.WriteString(fgColor.Sprint(color.Sprintf(ct)))
+ }
+ if j < xAmount {
+ if !p.Boxed && p.HasHeader && j == xAmount-1 {
+ continue
+ }
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ if p.Boxed && !p.HasHeader && j == xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+
+ if i < yAmount {
+ if p.HasHeader && i == yAmount-1 {
+ continue
+ }
+ buffer.WriteString("\n")
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LSeparator))
+ }
+ if p.Grid {
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TCrossSeparator))
+ }
+ }
+ }
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LReverseSeparator))
+ }
+ if p.Grid {
+ buffer.WriteString("\n")
+ }
+ }
+ }
+}
+
+func (p HeatmapPrinter) generateLegend(buffer *bytes.Buffer, legend string, legendColWidth int) {
+ buffer.WriteString(p.AxisStyle.Sprint(legend))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ } else {
+ buffer.WriteString(" ")
+ }
+ if p.EnableRGB {
+ p.generateRGBLegend(buffer, legendColWidth)
+ } else {
+ p.generateColorLegend(buffer, legendColWidth)
+ }
+}
+
+func (p HeatmapPrinter) generateColorLegend(buffer *bytes.Buffer, legendColWidth int) {
+ for i, color := range p.Colors {
+ // the first color is the min value and the last color is the max value
+ var f float32
+ if i == 0 {
+ f = p.minValue
+ } else if i == len(p.Colors)-1 {
+ f = p.maxValue
+ } else {
+ f = p.minValue + (p.maxValue-p.minValue)*float32(i)/float32(len(p.Colors)-1)
+ }
+ fgColor := p.TextColor
+ if p.EnableComplementaryColor {
+ fgColor = complementaryColors[color]
+ }
+ buffer.WriteString(fgColor.Sprint(color.Sprint(centerAndShorten(f, legendColWidth, p.LegendOnlyColoredCells))))
+ if p.Grid && i < len(p.Colors)-1 && !p.LegendOnlyColoredCells {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ }
+ }
+}
+
+func (p HeatmapPrinter) generateRGBLegend(buffer *bytes.Buffer, legendColWidth int) {
+ p.rgbLegendValue = 10
+ steps := len(p.RGBRange)
+ if steps < p.rgbLegendValue {
+ steps = p.rgbLegendValue
+ }
+ if p.LegendOnlyColoredCells {
+ steps *= 3
+ }
+ for i := 0; i < steps; i++ {
+ // the first color is the min value and the last color is the max value
+ var f float32
+ if i == 0 {
+ f = p.minValue
+ } else if i == steps-1 {
+ f = p.maxValue
+ } else {
+ f = p.minValue + (p.maxValue-p.minValue)*float32(i)/float32(steps-1)
+ }
+ rgb := p.RGBRange[0].Fade(p.minValue, p.maxValue, f, p.RGBRange[1:]...)
+ rgbStyle := NewRGBStyle(p.TextRGB, rgb)
+ if p.EnableComplementaryColor {
+ complimentary := NewRGB(internal.Complementary(rgb.R, rgb.G, rgb.B))
+ rgbStyle = NewRGBStyle(complimentary, rgb)
+ }
+ if p.LegendOnlyColoredCells {
+ buffer.WriteString(rgbStyle.Sprint(centerAndShorten(f, 1, p.LegendOnlyColoredCells)))
+ } else {
+ buffer.WriteString(rgbStyle.Sprint(centerAndShorten(f, legendColWidth, p.LegendOnlyColoredCells)))
+ }
+ if p.Grid && i < steps-1 && !p.LegendOnlyColoredCells {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ }
+ }
+}
+
+func (p HeatmapPrinter) boxLegend(buffer *bytes.Buffer, legend string, legendColWidth int) {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.BottomRightCornerSeparator))
+
+ p.generateSeparatorRow(buffer, legend, legendColWidth, true)
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.BottomLeftCornerSeparator))
+ buffer.WriteString("\n")
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+
+ p.generateLegend(buffer, legend, legendColWidth)
+
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ buffer.WriteString("\n")
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TopRightCornerSeparator))
+
+ p.generateSeparatorRow(buffer, legend, legendColWidth, false)
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TopLeftCornerSeparator))
+}
+
+func (p HeatmapPrinter) generateSeparatorRow(buffer *bytes.Buffer, legend string, legendColWidth int, top bool) {
+ p.rgbLegendValue = 10
+ steps := len(p.RGBRange)
+ if steps < p.rgbLegendValue {
+ steps = p.rgbLegendValue
+ }
+ if p.LegendOnlyColoredCells {
+ steps *= 3
+ }
+
+ var xValue int
+ if p.EnableRGB {
+ xValue = len(p.RGBRange)
+ if xValue < p.rgbLegendValue {
+ xValue = p.rgbLegendValue
+ }
+ } else {
+ xValue = len(p.Colors)
+ }
+
+ for i := 0; i < xValue+1; i++ {
+ if i == 0 {
+ firstLength := len(legend)
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), firstLength))
+ } else {
+ if p.LegendOnlyColoredCells {
+ if p.EnableRGB {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), steps/(xValue)))
+ } else {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), legendColWidth))
+ }
+ } else {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), legendColWidth))
+ }
+ }
+ if i < xValue && !p.LegendOnlyColoredCells || i == 0 {
+ if top {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TSeparator))
+ } else {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TReverseSeparator))
+ }
+ }
+ }
+}
+
+func centerAndShorten(f float32, lineLength int, onlyColor bool) string {
+ value := ""
+ if !onlyColor {
+ value = Sprintf("%.2v", f)
+ }
+ if len(value) > lineLength {
+ value = value[:lineLength]
+ if strings.HasSuffix(value, ".") {
+ value = Sprintf("%.1v", f)
+ lineLength = len(value)
+ }
+ }
+ ct := internal.CenterText(value, lineLength)
+ if len(ct) < lineLength {
+ if len(Sprintf("%v", f)) == 1 {
+ ct += strings.Repeat(" ", lineLength-len(ct))
+ } else {
+ ct = strings.Repeat(" ", lineLength-len(ct)) + ct
+ }
+ }
+
+ return ct
+}
+
+func getColor(min float32, max float32, current float32, colors ...Color) Color {
+ // split the range into equal parts
+ // and assign a color to each part
+ // the last color is assigned to the max value
+ // and the first color to the min value
+ // the rest of the colors are assigned to the
+ // middle values
+ step := (max - min) / float32(len(colors))
+ for i := range colors {
+ if current >= min+float32(i)*step && current < min+float32(i+1)*step {
+ return colors[i]
+ }
+ }
+ return colors[len(colors)-1]
+}
+
+// Render prints the HeatmapPrinter to the terminal.
+func (p HeatmapPrinter) Render() error {
+ s, err := p.Srender()
+ if err != nil {
+ return err
+ }
+ Fprintln(p.Writer, s)
+
+ return nil
+}
+
+func (p HeatmapPrinter) errCheck() error {
+ if p.HasHeader {
+ if p.Axis.XAxis == nil {
+ return errors.New("x axis is nil")
+ }
+ if p.Axis.YAxis == nil {
+ return errors.New("y axis is nil")
+ }
+
+ if len(p.Axis.XAxis) == 0 {
+ return errors.New("x axis is empty")
+ }
+ if len(p.Axis.YAxis) == 0 {
+ return errors.New("y axis is empty")
+ }
+
+ for i := 1; i < len(p.Data); i++ {
+ if len(p.Data[i]) != len(p.Axis.XAxis) {
+ return errors.New("x axis length does not match data")
+ }
+ }
+ if len(p.Axis.YAxis) != len(p.Data) {
+ return errors.New("y axis length does not match data")
+ }
+ }
+
+ if p.Data == nil {
+ return errors.New("data is nil")
+ }
+
+ if len(p.Data) == 0 {
+ return errors.New("data is empty")
+ }
+
+ // check if p.Data[n] has the same length
+ for i := 1; i < len(p.Data); i++ {
+ if len(p.Data[i]) != len(p.Data[0]) {
+ return errors.New("data is not rectangular")
+ }
+ }
+
+ return nil
+}
+
+// return min and max value of a slice
+func minMaxFloat32(s [][]float32) (float32, float32) {
+ var min, max float32
+ min = math.MaxFloat32
+ max = -math.MaxFloat32
+
+ for _, r := range s {
+ for _, c := range r {
+ if c < min {
+ min = c
+ }
+ if c > max {
+ max = c
+ }
+ }
+ }
+ return min, max
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_confirm_printer.go b/vendor/github.com/pterm/pterm/interactive_confirm_printer.go
index 6760ce69..a94cc5dc 100644
--- a/vendor/github.com/pterm/pterm/interactive_confirm_printer.go
+++ b/vendor/github.com/pterm/pterm/interactive_confirm_printer.go
@@ -7,35 +7,37 @@ import (
"atomicgo.dev/cursor"
"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
+
"github.com/pterm/pterm/internal"
)
-var (
- // DefaultInteractiveConfirm is the default InteractiveConfirm printer.
- // Pressing "y" will return true, "n" will return false.
- // Pressing enter without typing "y" or "n" will return the configured default value (by default set to "no").
- DefaultInteractiveConfirm = InteractiveConfirmPrinter{
- DefaultValue: false,
- DefaultText: "Please confirm",
- TextStyle: &ThemeDefault.PrimaryStyle,
- ConfirmText: "Yes",
- ConfirmStyle: &ThemeDefault.SuccessMessageStyle,
- RejectText: "No",
- RejectStyle: &ThemeDefault.ErrorMessageStyle,
- SuffixStyle: &ThemeDefault.SecondaryStyle,
- }
-)
+// DefaultInteractiveConfirm is the default InteractiveConfirm printer.
+// Pressing "y" will return true, "n" will return false.
+// Pressing enter without typing "y" or "n" will return the configured default value (by default set to "no").
+var DefaultInteractiveConfirm = InteractiveConfirmPrinter{
+ DefaultValue: false,
+ DefaultText: "Please confirm",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ ConfirmText: "Yes",
+ ConfirmStyle: &ThemeDefault.SuccessMessageStyle,
+ RejectText: "No",
+ RejectStyle: &ThemeDefault.ErrorMessageStyle,
+ SuffixStyle: &ThemeDefault.SecondaryStyle,
+ Delimiter: ": ",
+}
// InteractiveConfirmPrinter is a printer for interactive confirm prompts.
type InteractiveConfirmPrinter struct {
- DefaultValue bool
- DefaultText string
- TextStyle *Style
- ConfirmText string
- ConfirmStyle *Style
- RejectText string
- RejectStyle *Style
- SuffixStyle *Style
+ DefaultValue bool
+ DefaultText string
+ Delimiter string
+ TextStyle *Style
+ ConfirmText string
+ ConfirmStyle *Style
+ RejectText string
+ RejectStyle *Style
+ SuffixStyle *Style
+ OnInterruptFunc func()
}
// WithDefaultText sets the default text.
@@ -86,6 +88,18 @@ func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveCon
return &p
}
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveConfirmPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveConfirmPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveConfirmPrinter) WithDelimiter(delimiter string) *InteractiveConfirmPrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
// Show shows the confirm prompt.
//
// Example:
@@ -95,7 +109,7 @@ func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveCon
func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
- cancel, exit := internal.NewCancelationSignal()
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()
var result bool
@@ -104,7 +118,7 @@ func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
text = []string{p.DefaultText}
}
- p.TextStyle.Print(text[0] + " " + p.getSuffix() + ": ")
+ p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
y, n := p.getShortHandles()
var interrupted bool
diff --git a/vendor/github.com/pterm/pterm/interactive_continue_printer.go b/vendor/github.com/pterm/pterm/interactive_continue_printer.go
index d0f91f13..4049cde9 100644
--- a/vendor/github.com/pterm/pterm/interactive_continue_printer.go
+++ b/vendor/github.com/pterm/pterm/interactive_continue_printer.go
@@ -2,7 +2,6 @@ package pterm
import (
"fmt"
- "os"
"strings"
"atomicgo.dev/cursor"
@@ -14,24 +13,24 @@ import (
"github.com/pterm/pterm/internal"
)
-var (
- // DefaultInteractiveContinue is the default InteractiveContinue printer.
- // Pressing "y" will return yes, "n" will return no, "a" returns all and "s" returns stop.
- // Pressing enter without typing any letter will return the configured default value (by default set to "yes", the fisrt option).
- DefaultInteractiveContinue = InteractiveContinuePrinter{
- DefaultValueIndex: 0,
- DefaultText: "Do you want to continue",
- TextStyle: &ThemeDefault.PrimaryStyle,
- Options: []string{"yes", "no", "all", "cancel"},
- OptionsStyle: &ThemeDefault.SuccessMessageStyle,
- SuffixStyle: &ThemeDefault.SecondaryStyle,
- }
-)
+// DefaultInteractiveContinue is the default InteractiveContinue printer.
+// Pressing "y" will return yes, "n" will return no, "a" returns all and "s" returns stop.
+// Pressing enter without typing any letter will return the configured default value (by default set to "yes", the fisrt option).
+var DefaultInteractiveContinue = InteractiveContinuePrinter{
+ DefaultValueIndex: 0,
+ DefaultText: "Do you want to continue",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ Options: []string{"yes", "no", "all", "cancel"},
+ OptionsStyle: &ThemeDefault.SuccessMessageStyle,
+ SuffixStyle: &ThemeDefault.SecondaryStyle,
+ Delimiter: ": ",
+}
// InteractiveContinuePrinter is a printer for interactive continue prompts.
type InteractiveContinuePrinter struct {
DefaultValueIndex int
DefaultText string
+ Delimiter string
TextStyle *Style
Options []string
OptionsStyle *Style
@@ -108,6 +107,12 @@ func (p InteractiveContinuePrinter) WithSuffixStyle(style *Style) *InteractiveCo
return &p
}
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveContinuePrinter) WithDelimiter(delimiter string) *InteractiveContinuePrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
// Show shows the continue prompt.
//
// Example:
@@ -121,7 +126,7 @@ func (p InteractiveContinuePrinter) Show(text ...string) (string, error) {
text = []string{p.DefaultText}
}
- p.TextStyle.Print(text[0] + " " + p.getSuffix() + ": ")
+ p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
err := keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
if err != nil {
@@ -149,7 +154,7 @@ func (p InteractiveContinuePrinter) Show(text ...string) (string, error) {
result = p.Options[p.DefaultValueIndex]
return true, nil
case keys.CtrlC:
- os.Exit(1)
+ internal.Exit(1)
return true, nil
}
return false, nil
diff --git a/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go b/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
index b55a92c8..754ba98a 100644
--- a/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
+++ b/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
@@ -32,16 +32,17 @@ var (
// InteractiveMultiselectPrinter is a printer for interactive multiselect menus.
type InteractiveMultiselectPrinter struct {
- DefaultText string
- TextStyle *Style
- Options []string
- OptionStyle *Style
- DefaultOptions []string
- MaxHeight int
- Selector string
- SelectorStyle *Style
- Filter bool
- Checkmark *Checkmark
+ DefaultText string
+ TextStyle *Style
+ Options []string
+ OptionStyle *Style
+ DefaultOptions []string
+ MaxHeight int
+ Selector string
+ SelectorStyle *Style
+ Filter bool
+ Checkmark *Checkmark
+ OnInterruptFunc func()
selectedOption int
selectedOptions []int
@@ -52,7 +53,10 @@ type InteractiveMultiselectPrinter struct {
displayedOptionsStart int
displayedOptionsEnd int
- KeySelect keys.KeyCode
+ // KeySelect is the select key. It cannot be keys.Space when Filter is enabled.
+ KeySelect keys.KeyCode
+
+ // KeyConfirm is the confirm key. It cannot be keys.Space when Filter is enabled.
KeyConfirm keys.KeyCode
}
@@ -81,18 +85,20 @@ func (p InteractiveMultiselectPrinter) WithMaxHeight(maxHeight int) *Interactive
}
// WithFilter sets the Filter option
-func (p InteractiveMultiselectPrinter) WithFilter(filter bool) *InteractiveMultiselectPrinter {
- p.Filter = filter
+func (p InteractiveMultiselectPrinter) WithFilter(b ...bool) *InteractiveMultiselectPrinter {
+ p.Filter = internal.WithBoolean(b)
return &p
}
// WithKeySelect sets the confirm key
+// It cannot be keys.Space when Filter is enabled.
func (p InteractiveMultiselectPrinter) WithKeySelect(keySelect keys.KeyCode) *InteractiveMultiselectPrinter {
p.KeySelect = keySelect
return &p
}
// WithKeyConfirm sets the confirm key
+// It cannot be keys.Space when Filter is enabled.
func (p InteractiveMultiselectPrinter) WithKeyConfirm(keyConfirm keys.KeyCode) *InteractiveMultiselectPrinter {
p.KeyConfirm = keyConfirm
return &p
@@ -104,11 +110,17 @@ func (p InteractiveMultiselectPrinter) WithCheckmark(checkmark *Checkmark) *Inte
return &p
}
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveMultiselectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveMultiselectPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
// Show shows the interactive multiselect menu and returns the selected entry.
func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
- cancel, exit := internal.NewCancelationSignal()
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()
if len(text) == 0 || Sprint(text[0]) == "" {
@@ -228,7 +240,7 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
p.selectedOptions = append(p.selectedOptions, i)
}
area.Update(p.renderSelectMenu())
- case keys.Up:
+ case keys.Up, keys.CtrlP:
if len(p.fuzzySearchMatches) == 0 {
return false, nil
}
@@ -251,7 +263,7 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
}
area.Update(p.renderSelectMenu())
- case keys.Down:
+ case keys.Down, keys.CtrlN:
if len(p.fuzzySearchMatches) == 0 {
return false, nil
}
@@ -279,7 +291,7 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
return false, nil
})
if err != nil {
- fmt.Println(err)
+ Error.Println(err)
return nil, fmt.Errorf("failed to start keyboard listener: %w", err)
}
diff --git a/vendor/github.com/pterm/pterm/interactive_select_printer.go b/vendor/github.com/pterm/pterm/interactive_select_printer.go
index 1745f13f..0c4bc995 100644
--- a/vendor/github.com/pterm/pterm/interactive_select_printer.go
+++ b/vendor/github.com/pterm/pterm/interactive_select_printer.go
@@ -23,19 +23,22 @@ var (
MaxHeight: 5,
Selector: ">",
SelectorStyle: &ThemeDefault.SecondaryStyle,
+ Filter: true,
}
)
// InteractiveSelectPrinter is a printer for interactive select menus.
type InteractiveSelectPrinter struct {
- TextStyle *Style
- DefaultText string
- Options []string
- OptionStyle *Style
- DefaultOption string
- MaxHeight int
- Selector string
- SelectorStyle *Style
+ TextStyle *Style
+ DefaultText string
+ Options []string
+ OptionStyle *Style
+ DefaultOption string
+ MaxHeight int
+ Selector string
+ SelectorStyle *Style
+ OnInterruptFunc func()
+ Filter bool
selectedOption int
result string
@@ -71,11 +74,23 @@ func (p InteractiveSelectPrinter) WithMaxHeight(maxHeight int) *InteractiveSelec
return &p
}
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveSelectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveSelectPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithFilter sets the Filter option
+func (p InteractiveSelectPrinter) WithFilter(b ...bool) *InteractiveSelectPrinter {
+ p.Filter = internal.WithBoolean(b)
+ return &p
+}
+
// Show shows the interactive select menu and returns the selected entry.
func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
- cancel, exit := internal.NewCancelationSignal()
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()
if len(text) == 0 || Sprint(text[0]) == "" {
@@ -142,14 +157,16 @@ func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
switch key {
case keys.RuneKey:
- // Fuzzy search for options
- // append to fuzzy search string
- p.fuzzySearchString += keyInfo.String()
- p.selectedOption = 0
- p.displayedOptionsStart = 0
- p.displayedOptionsEnd = maxHeight
- p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
- area.Update(p.renderSelectMenu())
+ if p.Filter {
+ // Fuzzy search for options
+ // append to fuzzy search string
+ p.fuzzySearchString += keyInfo.String()
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
+ area.Update(p.renderSelectMenu())
+ }
case keys.Space:
p.fuzzySearchString += " "
p.selectedOption = 0
@@ -179,7 +196,7 @@ func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
area.Update(p.renderSelectMenu())
- case keys.Up:
+ case keys.Up, keys.CtrlP:
if len(p.fuzzySearchMatches) == 0 {
return false, nil
}
@@ -202,7 +219,7 @@ func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
}
area.Update(p.renderSelectMenu())
- case keys.Down:
+ case keys.Down, keys.CtrlN:
if len(p.fuzzySearchMatches) == 0 {
return false, nil
}
@@ -236,7 +253,7 @@ func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
return false, nil
})
if err != nil {
- fmt.Println(err)
+ Error.Println(err)
return "", fmt.Errorf("failed to start keyboard listener: %w", err)
}
@@ -245,7 +262,11 @@ func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
func (p *InteractiveSelectPrinter) renderSelectMenu() string {
var content string
- content += Sprintf("%s %s: %s\n", p.text, p.SelectorStyle.Sprint("[type to search]"), p.fuzzySearchString)
+ if p.Filter {
+ content += Sprintf("%s %s: %s\n", p.text, p.SelectorStyle.Sprint("[type to search]"), p.fuzzySearchString)
+ } else {
+ content += Sprintf("%s:\n", p.text)
+ }
// find options that match fuzzy search string
rankedResults := fuzzy.RankFindFold(p.fuzzySearchString, p.Options)
diff --git a/vendor/github.com/pterm/pterm/interactive_textinput_printer.go b/vendor/github.com/pterm/pterm/interactive_textinput_printer.go
index e7174555..88535c51 100644
--- a/vendor/github.com/pterm/pterm/interactive_textinput_printer.go
+++ b/vendor/github.com/pterm/pterm/interactive_textinput_printer.go
@@ -10,19 +10,23 @@ import (
"github.com/pterm/pterm/internal"
)
-var (
- // DefaultInteractiveTextInput is the default InteractiveTextInput printer.
- DefaultInteractiveTextInput = InteractiveTextInputPrinter{
- DefaultText: "Input text",
- TextStyle: &ThemeDefault.PrimaryStyle,
- }
-)
+// DefaultInteractiveTextInput is the default InteractiveTextInput printer.
+var DefaultInteractiveTextInput = InteractiveTextInputPrinter{
+ DefaultText: "Input text",
+ Delimiter: ": ",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ Mask: "",
+}
// InteractiveTextInputPrinter is a printer for interactive select menus.
type InteractiveTextInputPrinter struct {
- TextStyle *Style
- DefaultText string
- MultiLine bool
+ TextStyle *Style
+ DefaultText string
+ DefaultValue string
+ Delimiter string
+ MultiLine bool
+ Mask string
+ OnInterruptFunc func()
input []string
cursorXPos int
@@ -36,6 +40,12 @@ func (p InteractiveTextInputPrinter) WithDefaultText(text string) *InteractiveTe
return &p
}
+// WithDefaultValue sets the default value.
+func (p InteractiveTextInputPrinter) WithDefaultValue(value string) *InteractiveTextInputPrinter {
+ p.DefaultValue = value
+ return &p
+}
+
// WithTextStyle sets the text style.
func (p InteractiveTextInputPrinter) WithTextStyle(style *Style) *InteractiveTextInputPrinter {
p.TextStyle = style
@@ -48,11 +58,29 @@ func (p InteractiveTextInputPrinter) WithMultiLine(multiLine ...bool) *Interacti
return &p
}
+// WithMask sets the mask.
+func (p InteractiveTextInputPrinter) WithMask(mask string) *InteractiveTextInputPrinter {
+ p.Mask = mask
+ return &p
+}
+
+// WithOnInterruptFunc sets the function to execute on exit of the input reader
+func (p InteractiveTextInputPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveTextInputPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveTextInputPrinter) WithDelimiter(delimiter string) *InteractiveTextInputPrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
// Show shows the interactive select menu and returns the selected entry.
func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
- cancel, exit := internal.NewCancelationSignal()
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()
var areaText string
@@ -62,24 +90,26 @@ func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
}
if p.MultiLine {
- areaText = p.TextStyle.Sprintfln("%s %s :", text[0], ThemeDefault.SecondaryStyle.Sprint("[Press tab to submit]"))
+ areaText = p.TextStyle.Sprintfln("%s %s %s", text[0], ThemeDefault.SecondaryStyle.Sprint("[Press tab to submit]"), p.Delimiter)
} else {
- areaText = p.TextStyle.Sprintf("%s: ", text[0])
+ areaText = p.TextStyle.Sprintf("%s%s", text[0], p.Delimiter)
}
+
p.text = areaText
- area, err := DefaultArea.Start(areaText)
- defer area.Stop()
- if err != nil {
- return "", err
- }
+ area := cursor.NewArea()
+ area.Update(areaText)
+ area.StartOfLine()
- cursor.Up(1)
- cursor.StartOfLine()
if !p.MultiLine {
cursor.Right(len(RemoveColorFromString(areaText)))
}
- err = keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if p.DefaultValue != "" {
+ p.input = append(p.input, p.DefaultValue)
+ p.updateArea(&area)
+ }
+
+ err := keyboard.Listen(func(key keys.Key) (stop bool, err error) {
if !p.MultiLine {
p.cursorYPos = 0
}
@@ -90,6 +120,7 @@ func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
switch key.Code {
case keys.Tab:
if p.MultiLine {
+ area.Bottom()
return true, nil
}
case keys.Enter:
@@ -104,7 +135,6 @@ func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
p.input = append(p.input, appendAfterY...)
p.cursorYPos++
p.cursorXPos = -internal.GetStringMaxWidth(p.input[p.cursorYPos])
- cursor.Down(1)
cursor.StartOfLine()
} else {
return true, nil
@@ -173,7 +203,7 @@ func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
}
}
- p.updateArea(area)
+ p.updateArea(&area)
return false, nil
})
@@ -195,11 +225,12 @@ func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
return strings.ReplaceAll(areaText, p.text, ""), nil
}
-func (p InteractiveTextInputPrinter) updateArea(area *AreaPrinter) string {
+func (p InteractiveTextInputPrinter) updateArea(area *cursor.Area) string {
if !p.MultiLine {
p.cursorYPos = 0
}
areaText := p.text
+
for i, s := range p.input {
if i < len(p.input)-1 {
areaText += s + "\n"
@@ -207,14 +238,19 @@ func (p InteractiveTextInputPrinter) updateArea(area *AreaPrinter) string {
areaText += s
}
}
+
+ if p.Mask != "" {
+ areaText = p.text + strings.Repeat(p.Mask, internal.GetStringMaxWidth(areaText)-internal.GetStringMaxWidth(p.text))
+ }
+
if p.cursorXPos+internal.GetStringMaxWidth(p.input[p.cursorYPos]) < 1 {
p.cursorXPos = -internal.GetStringMaxWidth(p.input[p.cursorYPos])
}
- cursor.StartOfLine()
area.Update(areaText)
- cursor.Up(len(p.input) - p.cursorYPos)
- cursor.StartOfLine()
+ area.Top()
+ area.Down(p.cursorYPos + 1)
+ area.StartOfLine()
if p.MultiLine {
cursor.Right(internal.GetStringMaxWidth(p.input[p.cursorYPos]) + p.cursorXPos)
} else {
diff --git a/vendor/github.com/pterm/pterm/interface_live_printer.go b/vendor/github.com/pterm/pterm/interface_live_printer.go
index b8d3dbe3..69dce345 100644
--- a/vendor/github.com/pterm/pterm/interface_live_printer.go
+++ b/vendor/github.com/pterm/pterm/interface_live_printer.go
@@ -1,5 +1,7 @@
package pterm
+import "io"
+
// LivePrinter is a printer which can update it's output live.
type LivePrinter interface {
// GenericStart runs Start, but returns a LivePrinter.
@@ -11,4 +13,6 @@ type LivePrinter interface {
// This is used for the interface LivePrinter.
// You most likely want to use Stop instead of this in your program.
GenericStop() (*LivePrinter, error)
+
+ SetWriter(writer io.Writer)
}
diff --git a/vendor/github.com/pterm/pterm/internal/cancelation_signal.go b/vendor/github.com/pterm/pterm/internal/cancelation_signal.go
index d6f79b0a..33f17cc1 100644
--- a/vendor/github.com/pterm/pterm/internal/cancelation_signal.go
+++ b/vendor/github.com/pterm/pterm/internal/cancelation_signal.go
@@ -1,19 +1,20 @@
package internal
-import (
- "os"
-)
-
// NewCancelationSignal for keeping track of a cancelation
-func NewCancelationSignal() (func(), func()) {
+func NewCancelationSignal(interruptFunc func()) (func(), func()) {
canceled := false
cancel := func() {
canceled = true
}
+
exit := func() {
if canceled {
- os.Exit(1)
+ if interruptFunc != nil {
+ interruptFunc()
+ } else {
+ Exit(1)
+ }
}
}
diff --git a/vendor/github.com/pterm/pterm/internal/exit.go b/vendor/github.com/pterm/pterm/internal/exit.go
new file mode 100644
index 00000000..f07a0045
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/exit.go
@@ -0,0 +1,14 @@
+package internal
+
+import "os"
+
+// ExitFuncType is the type of function used to exit the program.
+type ExitFuncType func(int)
+
+// DefaultExitFunc is the default function used to exit the program.
+var DefaultExitFunc ExitFuncType = os.Exit
+
+// Exit calls the current exit function.
+func Exit(code int) {
+ DefaultExitFunc(code)
+}
diff --git a/vendor/github.com/pterm/pterm/internal/max_text_width.go b/vendor/github.com/pterm/pterm/internal/max_text_width.go
index fe394750..1d4f0ea3 100644
--- a/vendor/github.com/pterm/pterm/internal/max_text_width.go
+++ b/vendor/github.com/pterm/pterm/internal/max_text_width.go
@@ -1,10 +1,9 @@
package internal
import (
- "strings"
-
"github.com/gookit/color"
"github.com/mattn/go-runewidth"
+ "strings"
)
// GetStringMaxWidth returns the maximum width of a string with multiple lines.
@@ -12,8 +11,9 @@ func GetStringMaxWidth(s string) int {
var max int
ss := strings.Split(s, "\n")
for _, s2 := range ss {
- if runewidth.StringWidth(color.ClearCode(s2)) > max {
- max = runewidth.StringWidth(color.ClearCode(s2))
+ s2WithoutColor := color.ClearCode(s2)
+ if runewidth.StringWidth(s2WithoutColor) > max {
+ max = runewidth.StringWidth(s2WithoutColor)
}
}
return max
diff --git a/vendor/github.com/pterm/pterm/internal/rgb_complementary.go b/vendor/github.com/pterm/pterm/internal/rgb_complementary.go
new file mode 100644
index 00000000..71520b33
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/rgb_complementary.go
@@ -0,0 +1,5 @@
+package internal
+
+func Complementary(r, g, b uint8) (uint8, uint8, uint8) {
+ return 255 - r, 255 - g, 255 - b
+}
diff --git a/vendor/github.com/pterm/pterm/internal/title_in_line.go b/vendor/github.com/pterm/pterm/internal/title_in_line.go
index 3aae546b..68e28ec6 100644
--- a/vendor/github.com/pterm/pterm/internal/title_in_line.go
+++ b/vendor/github.com/pterm/pterm/internal/title_in_line.go
@@ -2,17 +2,15 @@ package internal
import (
"strings"
-
- "github.com/gookit/color"
)
// AddTitleToLine adds a title to a site of a line ex: "─ This is the title ──────"
func AddTitleToLine(title, line string, length int, left bool) string {
var ret string
if left {
- ret += line + " " + title + " " + line + strings.Repeat(line, length-(4+len(color.ClearCode(title))))
+ ret += line + " " + title + " " + line + strings.Repeat(line, length-(4+GetStringMaxWidth(title)))
} else {
- ret += strings.Repeat(line, length-(4+len(color.ClearCode(title)))) + line + " " + title + " " + line
+ ret += strings.Repeat(line, length-(4+GetStringMaxWidth(title))) + line + " " + title + " " + line
}
return ret
@@ -21,7 +19,7 @@ func AddTitleToLine(title, line string, length int, left bool) string {
// AddTitleToLineCenter adds a title to the center of a line ex: "─ This is the title ──────"
func AddTitleToLineCenter(title, line string, length int) string {
var ret string
- repeatString := length - (4 + len(color.ClearCode(title)))
+ repeatString := length - (4 + GetStringMaxWidth(title))
unevenRepeatString := repeatString % 2
ret += strings.Repeat(line, repeatString/2) + line + " " + title + " " + line + strings.Repeat(line, repeatString/2+unevenRepeatString)
diff --git a/vendor/github.com/pterm/pterm/logger.go b/vendor/github.com/pterm/pterm/logger.go
new file mode 100644
index 00000000..26eea5b0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/logger.go
@@ -0,0 +1,431 @@
+package pterm
+
+import (
+ "encoding/json"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/pterm/pterm/internal"
+)
+
+type LogLevel int
+
+// Style returns the style of the log level.
+func (l LogLevel) Style() Style {
+ baseStyle := NewStyle(Bold)
+ switch l {
+ case LogLevelTrace:
+ return baseStyle.Add(*FgCyan.ToStyle())
+ case LogLevelDebug:
+ return baseStyle.Add(*FgBlue.ToStyle())
+ case LogLevelInfo:
+ return baseStyle.Add(*FgGreen.ToStyle())
+ case LogLevelWarn:
+ return baseStyle.Add(*FgYellow.ToStyle())
+ case LogLevelError:
+ return baseStyle.Add(*FgRed.ToStyle())
+ case LogLevelFatal:
+ return baseStyle.Add(*FgRed.ToStyle())
+ case LogLevelPrint:
+ return baseStyle.Add(*FgWhite.ToStyle())
+ }
+
+ return baseStyle.Add(*FgWhite.ToStyle())
+}
+
+func (l LogLevel) String() string {
+ switch l {
+ case LogLevelDisabled:
+ return ""
+ case LogLevelTrace:
+ return "TRACE"
+ case LogLevelDebug:
+ return "DEBUG"
+ case LogLevelInfo:
+ return "INFO"
+ case LogLevelWarn:
+ return "WARN"
+ case LogLevelError:
+ return "ERROR"
+ case LogLevelFatal:
+ return "FATAL"
+ case LogLevelPrint:
+ return "PRINT"
+ }
+ return "Unknown"
+}
+
+const (
+ // LogLevelDisabled does never print.
+ LogLevelDisabled LogLevel = iota
+ // LogLevelTrace is the log level for traces.
+ LogLevelTrace
+ // LogLevelDebug is the log level for debug.
+ LogLevelDebug
+ // LogLevelInfo is the log level for info.
+ LogLevelInfo
+ // LogLevelWarn is the log level for warnings.
+ LogLevelWarn
+ // LogLevelError is the log level for errors.
+ LogLevelError
+ // LogLevelFatal is the log level for fatal errors.
+ LogLevelFatal
+ // LogLevelPrint is the log level for printing.
+ LogLevelPrint
+)
+
+// LogFormatter is the log formatter.
+// Can be either LogFormatterColorful or LogFormatterJSON.
+type LogFormatter int
+
+const (
+ // LogFormatterColorful is a colorful log formatter.
+ LogFormatterColorful LogFormatter = iota
+ // LogFormatterJSON is a JSON log formatter.
+ LogFormatterJSON
+)
+
+// DefaultLogger is the default logger.
+var DefaultLogger = Logger{
+ Formatter: LogFormatterColorful,
+ Writer: os.Stdout,
+ Level: LogLevelInfo,
+ ShowTime: true,
+ TimeFormat: "2006-01-02 15:04:05",
+ MaxWidth: 80,
+ KeyStyles: map[string]Style{
+ "error": *NewStyle(FgRed, Bold),
+ "err": *NewStyle(FgRed, Bold),
+ "caller": *NewStyle(FgGray, Bold),
+ },
+}
+
+// loggerMutex syncs all loggers, so that they don't print at the exact same time.
+var loggerMutex sync.Mutex
+
+type Logger struct {
+ // Formatter is the log formatter of the logger.
+ Formatter LogFormatter
+ // Writer is the writer of the logger.
+ Writer io.Writer
+ // Level is the log level of the logger.
+ Level LogLevel
+ // ShowCaller defines if the logger should print the caller.
+ ShowCaller bool
+ // CallerOffset defines the offset of the caller.
+ CallerOffset int
+ // ShowTime defines if the logger should print a timestamp.
+ ShowTime bool
+ // TimestampLayout defines the layout of the timestamp.
+ TimeFormat string
+ // KeyStyles defines the styles for specific keys.
+ KeyStyles map[string]Style
+ // MaxWidth defines the maximum width of the logger.
+ // If the text (including the arguments) is longer than the max width, it will be split into multiple lines.
+ MaxWidth int
+}
+
+// WithFormatter sets the log formatter of the logger.
+func (l Logger) WithFormatter(formatter LogFormatter) *Logger {
+ l.Formatter = formatter
+ return &l
+}
+
+// WithWriter sets the writer of the logger.
+func (l Logger) WithWriter(writer io.Writer) *Logger {
+ l.Writer = writer
+ return &l
+}
+
+// WithLevel sets the log level of the logger.
+func (l Logger) WithLevel(level LogLevel) *Logger {
+ l.Level = level
+ return &l
+}
+
+// WithCaller enables or disables the caller.
+func (l Logger) WithCaller(b ...bool) *Logger {
+ l.ShowCaller = internal.WithBoolean(b)
+ return &l
+}
+
+// WithCallerOffset sets the caller offset.
+func (l Logger) WithCallerOffset(offset int) *Logger {
+ l.CallerOffset = offset
+ return &l
+}
+
+// WithTime enables or disables the timestamp.
+func (l Logger) WithTime(b ...bool) *Logger {
+ l.ShowTime = internal.WithBoolean(b)
+ return &l
+}
+
+// WithTimeFormat sets the timestamp layout.
+func (l Logger) WithTimeFormat(format string) *Logger {
+ l.TimeFormat = format
+ return &l
+}
+
+// WithKeyStyles sets the style for a specific key.
+func (l Logger) WithKeyStyles(styles map[string]Style) *Logger {
+ l.KeyStyles = styles
+ return &l
+}
+
+// WithMaxWidth sets the maximum width of the logger.
+func (l Logger) WithMaxWidth(width int) *Logger {
+ l.MaxWidth = width
+ return &l
+}
+
+// AppendKeyStyles appends a style for a specific key.
+func (l Logger) AppendKeyStyles(styles map[string]Style) *Logger {
+ for k, v := range styles {
+ l.KeyStyles[k] = v
+ }
+ return &l
+}
+
+// AppendKeyStyle appends a style for a specific key.
+func (l Logger) AppendKeyStyle(key string, style Style) *Logger {
+ l.KeyStyles[key] = style
+ return &l
+}
+
+// CanPrint checks if the logger can print a specific log level.
+func (l Logger) CanPrint(level LogLevel) bool {
+ if l.Level == LogLevelDisabled {
+ return false
+ }
+ return l.Level <= level
+}
+
+// Args converts any arguments to a slice of LoggerArgument.
+func (l Logger) Args(args ...any) []LoggerArgument {
+ var loggerArgs []LoggerArgument
+
+ // args are in the format of: key, value, key, value, key, value, ...
+ for i := 0; i < len(args); i += 2 {
+ key := Sprint(args[i])
+ value := args[i+1]
+
+ loggerArgs = append(loggerArgs, LoggerArgument{
+ Key: key,
+ Value: value,
+ })
+ }
+
+ return loggerArgs
+}
+
+// ArgsFromMap converts a map to a slice of LoggerArgument.
+func (l Logger) ArgsFromMap(m map[string]any) []LoggerArgument {
+ var loggerArgs []LoggerArgument
+
+ for k, v := range m {
+ loggerArgs = append(loggerArgs, LoggerArgument{
+ Key: k,
+ Value: v,
+ })
+ }
+
+ return loggerArgs
+}
+
+func (l Logger) getCallerInfo() (path string, line int) {
+ if !l.ShowCaller {
+ return
+ }
+
+ _, path, line, _ = runtime.Caller(l.CallerOffset + 4)
+ _, callerBase, _, _ := runtime.Caller(0)
+ basepath := filepath.Dir(callerBase)
+ basepath = strings.ReplaceAll(basepath, "\\", "/")
+
+ path = strings.TrimPrefix(path, basepath)
+
+ return
+}
+
+func (l Logger) combineArgs(args ...[]LoggerArgument) []LoggerArgument {
+ var result []LoggerArgument
+
+ for _, arg := range args {
+ result = append(result, arg...)
+ }
+
+ return result
+}
+
+func (l Logger) print(level LogLevel, msg string, args []LoggerArgument) {
+ if !l.CanPrint(level) {
+ return
+ }
+
+ var line string
+
+ switch l.Formatter {
+ case LogFormatterColorful:
+ line = l.renderColorful(level, msg, args)
+ case LogFormatterJSON:
+ line = l.renderJSON(level, msg, args)
+ }
+
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+
+ _, _ = l.Writer.Write([]byte(line + "\n"))
+}
+
+func (l Logger) renderColorful(level LogLevel, msg string, args []LoggerArgument) (result string) {
+ if l.ShowTime {
+ result += Gray(time.Now().Format(l.TimeFormat)) + " "
+ }
+
+ if GetTerminalWidth() > 0 && GetTerminalWidth() < l.MaxWidth {
+ l.MaxWidth = GetTerminalWidth()
+ }
+
+ var argumentsInNewLine bool
+
+ result += level.Style().Sprintf("%-5s", level.String()) + " "
+
+ // if msg is too long, wrap it to multiple lines with the same length
+ remainingWidth := l.MaxWidth - internal.GetStringMaxWidth(result)
+ if internal.GetStringMaxWidth(msg) > remainingWidth {
+ argumentsInNewLine = true
+ msg = DefaultParagraph.WithMaxWidth(remainingWidth).Sprint(msg)
+ padding := len(time.Now().Format(l.TimeFormat) + " ")
+ msg = strings.ReplaceAll(msg, "\n", "\n"+strings.Repeat(" ", padding)+" │ ")
+ }
+
+ result += msg
+
+ if l.ShowCaller {
+ path, line := l.getCallerInfo()
+ args = append(args, LoggerArgument{
+ Key: "caller",
+ Value: FgGray.Sprintf("%s:%d", path, line),
+ })
+ }
+
+ arguments := make([]string, len(args))
+
+ // add arguments
+ if len(args) > 0 {
+ for i, arg := range args {
+ if style, ok := l.KeyStyles[arg.Key]; ok {
+ arguments[i] = style.Sprintf("%s: ", arg.Key)
+ } else {
+ arguments[i] = level.Style().Sprintf("%s: ", arg.Key)
+ }
+
+ arguments[i] += Sprintf("%s", Sprint(arg.Value))
+ }
+ }
+
+ fullLine := result + " " + strings.Join(arguments, " ")
+
+ // if the full line is too long, wrap the arguments to multiple lines
+ if internal.GetStringMaxWidth(fullLine) > l.MaxWidth {
+ argumentsInNewLine = true
+ }
+
+ if !argumentsInNewLine {
+ result = fullLine
+ } else {
+ padding := 4
+ if l.ShowTime {
+ padding = len(time.Time{}.Format(l.TimeFormat)) + 3
+ }
+
+ for i, argument := range arguments {
+ var pipe string
+ if i < len(arguments)-1 {
+ pipe = "├"
+ } else {
+ pipe = "└"
+ }
+ result += "\n" + strings.Repeat(" ", padding) + pipe + " " + argument
+ }
+ }
+
+ return
+}
+
+func (l Logger) renderJSON(level LogLevel, msg string, args []LoggerArgument) string {
+ m := l.argsToMap(args)
+
+ m["level"] = level.String()
+ m["timestamp"] = time.Now().Format(l.TimeFormat)
+ m["msg"] = msg
+
+ if file, line := l.getCallerInfo(); file != "" {
+ m["caller"] = Sprintf("%s:%d", file, line)
+ }
+
+ b, _ := json.Marshal(m)
+ return string(b)
+}
+
+func (l Logger) argsToMap(args []LoggerArgument) map[string]any {
+ m := make(map[string]any)
+
+ for _, arg := range args {
+ m[arg.Key] = arg.Value
+ }
+
+ return m
+}
+
+// Trace prints a trace log.
+func (l Logger) Trace(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelTrace, msg, l.combineArgs(args...))
+}
+
+// Debug prints a debug log.
+func (l Logger) Debug(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelDebug, msg, l.combineArgs(args...))
+}
+
+// Info prints an info log.
+func (l Logger) Info(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelInfo, msg, l.combineArgs(args...))
+}
+
+// Warn prints a warning log.
+func (l Logger) Warn(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelWarn, msg, l.combineArgs(args...))
+}
+
+// Error prints an error log.
+func (l Logger) Error(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelError, msg, l.combineArgs(args...))
+}
+
+// Fatal prints a fatal log and exits the program.
+func (l Logger) Fatal(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelFatal, msg, l.combineArgs(args...))
+ if l.CanPrint(LogLevelFatal) {
+ os.Exit(1)
+ }
+}
+
+// Print prints a log.
+func (l Logger) Print(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelPrint, msg, l.combineArgs(args...))
+}
+
+// LoggerArgument is a key-value pair for a logger.
+type LoggerArgument struct {
+ // Key is the key of the argument.
+ Key string
+ // Value is the value of the argument.
+ Value any
+}
diff --git a/vendor/github.com/pterm/pterm/multi_live_printer.go b/vendor/github.com/pterm/pterm/multi_live_printer.go
new file mode 100644
index 00000000..b9e0d0e8
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/multi_live_printer.go
@@ -0,0 +1,124 @@
+package pterm
+
+import (
+ "atomicgo.dev/schedule"
+ "bytes"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+var DefaultMultiPrinter = MultiPrinter{
+ printers: []LivePrinter{},
+ Writer: os.Stdout,
+ UpdateDelay: time.Millisecond * 200,
+
+ buffers: []*bytes.Buffer{},
+ area: DefaultArea,
+}
+
+type MultiPrinter struct {
+ IsActive bool
+ Writer io.Writer
+ UpdateDelay time.Duration
+
+ printers []LivePrinter
+ buffers []*bytes.Buffer
+ area AreaPrinter
+}
+
+// SetWriter sets the writer for the AreaPrinter.
+func (p *MultiPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
+// WithWriter returns a fork of the MultiPrinter with a new writer.
+func (p MultiPrinter) WithWriter(writer io.Writer) *MultiPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// WithUpdateDelay returns a fork of the MultiPrinter with a new update delay.
+func (p MultiPrinter) WithUpdateDelay(delay time.Duration) *MultiPrinter {
+ p.UpdateDelay = delay
+ return &p
+}
+
+func (p *MultiPrinter) NewWriter() io.Writer {
+ buf := bytes.NewBufferString("")
+ p.buffers = append(p.buffers, buf)
+ return buf
+}
+
+// getString returns all buffers appended and separated by a newline.
+func (p *MultiPrinter) getString() string {
+ var buffer bytes.Buffer
+ for _, b := range p.buffers {
+ s := b.String()
+ s = strings.Trim(s, "\n")
+
+ parts := strings.Split(s, "\r") // only get the last override
+ s = parts[len(parts)-1]
+
+ // check if s is empty, if so get one part before, repeat until not empty
+ for s == "" {
+ parts = parts[:len(parts)-1]
+ s = parts[len(parts)-1]
+ }
+
+ s = strings.Trim(s, "\n\r")
+ buffer.WriteString(s)
+ buffer.WriteString("\n")
+ }
+ return buffer.String()
+}
+
+func (p *MultiPrinter) Start() (*MultiPrinter, error) {
+ p.IsActive = true
+ for _, printer := range p.printers {
+ printer.GenericStart()
+ }
+
+ schedule.Every(p.UpdateDelay, func() bool {
+ if !p.IsActive {
+ return false
+ }
+
+ p.area.Update(p.getString())
+
+ return true
+ })
+
+ return p, nil
+}
+
+func (p *MultiPrinter) Stop() (*MultiPrinter, error) {
+ p.IsActive = false
+ for _, printer := range p.printers {
+ printer.GenericStop()
+ }
+ time.Sleep(time.Millisecond * 20)
+ p.area.Update(p.getString())
+ p.area.Stop()
+
+ return p, nil
+}
+
+// GenericStart runs Start, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Start instead of this in your program.
+func (p MultiPrinter) GenericStart() (*LivePrinter, error) {
+ p2, _ := p.Start()
+ lp := LivePrinter(p2)
+ return &lp, nil
+}
+
+// GenericStop runs Stop, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Stop instead of this in your program.
+func (p MultiPrinter) GenericStop() (*LivePrinter, error) {
+ p2, _ := p.Stop()
+ lp := LivePrinter(p2)
+ return &lp, nil
+}
diff --git a/vendor/github.com/pterm/pterm/panel_printer.go b/vendor/github.com/pterm/pterm/panel_printer.go
index 709f7c80..090498e7 100644
--- a/vendor/github.com/pterm/pterm/panel_printer.go
+++ b/vendor/github.com/pterm/pterm/panel_printer.go
@@ -183,7 +183,7 @@ func (p PanelPrinter) Srender() (string, error) {
// Render prints the Template to the terminal.
func (p PanelPrinter) Render() error {
s, _ := p.Srender()
- Println(s)
+ Fprintln(p.Writer, s)
return nil
}
diff --git a/vendor/github.com/pterm/pterm/progressbar_printer.go b/vendor/github.com/pterm/pterm/progressbar_printer.go
index 2fb3f910..1cf4a0c2 100644
--- a/vendor/github.com/pterm/pterm/progressbar_printer.go
+++ b/vendor/github.com/pterm/pterm/progressbar_printer.go
@@ -1,8 +1,11 @@
package pterm
import (
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/schedule"
+ "fmt"
"io"
- "strconv"
+ "math"
"strings"
"time"
@@ -15,23 +18,21 @@ import (
// Generally, there should only be one active ProgressbarPrinter at a time.
var ActiveProgressBarPrinters []*ProgressbarPrinter
-var (
- // DefaultProgressbar is the default ProgressbarPrinter.
- DefaultProgressbar = ProgressbarPrinter{
- Total: 100,
- BarCharacter: "█",
- LastCharacter: "█",
- ElapsedTimeRoundingFactor: time.Second,
- BarStyle: &ThemeDefault.ProgressbarBarStyle,
- TitleStyle: &ThemeDefault.ProgressbarTitleStyle,
- ShowTitle: true,
- ShowCount: true,
- ShowPercentage: true,
- ShowElapsedTime: true,
- BarFiller: " ",
- MaxWidth: 80,
- }
-)
+// DefaultProgressbar is the default ProgressbarPrinter.
+var DefaultProgressbar = ProgressbarPrinter{
+ Total: 100,
+ BarCharacter: "█",
+ LastCharacter: "█",
+ ElapsedTimeRoundingFactor: time.Second,
+ BarStyle: &ThemeDefault.ProgressbarBarStyle,
+ TitleStyle: &ThemeDefault.ProgressbarTitleStyle,
+ ShowTitle: true,
+ ShowCount: true,
+ ShowPercentage: true,
+ ShowElapsedTime: true,
+ BarFiller: Gray("█"),
+ MaxWidth: 80,
+}
// ProgressbarPrinter shows a progress animation in the terminal.
type ProgressbarPrinter struct {
@@ -55,7 +56,8 @@ type ProgressbarPrinter struct {
IsActive bool
- startedAt time.Time
+ startedAt time.Time
+ rerenderTask *schedule.Task
Writer io.Writer
}
@@ -158,6 +160,11 @@ func (p ProgressbarPrinter) WithWriter(writer io.Writer) *ProgressbarPrinter {
return &p
}
+// SetWriter sets the custom Writer.
+func (p *ProgressbarPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
// Increment current value by one.
func (p *ProgressbarPrinter) Increment() *ProgressbarPrinter {
p.Add(1)
@@ -173,6 +180,14 @@ func (p *ProgressbarPrinter) UpdateTitle(title string) *ProgressbarPrinter {
// This is the update logic, renders the progressbar
func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
+ Fprinto(p.Writer, p.getString())
+ return p
+}
+
+func (p *ProgressbarPrinter) getString() string {
+ if !p.IsActive {
+ return ""
+ }
if p.TitleStyle == nil {
p.TitleStyle = NewStyle()
}
@@ -180,7 +195,7 @@ func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
p.BarStyle = NewStyle()
}
if p.Total == 0 {
- return nil
+ return ""
}
var before string
@@ -195,25 +210,20 @@ func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
width = p.MaxWidth
}
- currentPercentage := int(internal.PercentageRound(float64(int64(p.Total)), float64(int64(p.Current))))
-
- decoratorCount := Gray("[") + LightWhite(p.Current) + Gray("/") + LightWhite(p.Total) + Gray("]")
-
- decoratorCurrentPercentage := color.RGB(NewRGB(255, 0, 0).Fade(0, float32(p.Total), float32(p.Current), NewRGB(0, 255, 0)).GetValues()).
- Sprint(strconv.Itoa(currentPercentage) + "%")
-
- decoratorTitle := p.TitleStyle.Sprint(p.Title)
-
if p.ShowTitle {
- before += decoratorTitle + " "
+ before += p.TitleStyle.Sprint(p.Title) + " "
}
if p.ShowCount {
- before += decoratorCount + " "
+ padding := 1 + int(math.Log10(float64(p.Total)))
+ before += Gray("[") + LightWhite(fmt.Sprintf("%0*d", padding, p.Current)) + Gray("/") + LightWhite(p.Total) + Gray("]") + " "
}
after += " "
if p.ShowPercentage {
+ currentPercentage := int(internal.PercentageRound(float64(int64(p.Total)), float64(int64(p.Current))))
+ decoratorCurrentPercentage := color.RGB(NewRGB(255, 0, 0).Fade(0, float32(p.Total), float32(p.Current), NewRGB(0, 255, 0)).GetValues()).
+ Sprintf("%3d%%", currentPercentage)
after += decoratorCurrentPercentage + " "
}
if p.ShowElapsedTime {
@@ -228,17 +238,12 @@ func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
barFiller = strings.Repeat(p.BarFiller, barMaxLength-barCurrentLength)
}
- var bar string
+ bar := barFiller
if barCurrentLength > 0 {
- bar = p.BarStyle.Sprint(strings.Repeat(p.BarCharacter, barCurrentLength)+p.LastCharacter) + barFiller
- } else {
- bar = ""
+ bar = p.BarStyle.Sprint(strings.Repeat(p.BarCharacter, barCurrentLength)+p.LastCharacter) + bar
}
- if !RawOutput {
- Fprinto(p.Writer, before+bar+after)
- }
- return p
+ return before + bar + after
}
// Add to current value.
@@ -251,6 +256,8 @@ func (p *ProgressbarPrinter) Add(count int) *ProgressbarPrinter {
p.updateProgress()
if p.Current >= p.Total {
+ p.Total = p.Current
+ p.updateProgress()
p.Stop()
}
return p
@@ -258,6 +265,7 @@ func (p *ProgressbarPrinter) Add(count int) *ProgressbarPrinter {
// Start the ProgressbarPrinter.
func (p ProgressbarPrinter) Start(title ...interface{}) (*ProgressbarPrinter, error) {
+ cursor.Hide()
if RawOutput && p.ShowTitle {
Fprintln(p.Writer, p.Title)
}
@@ -270,11 +278,23 @@ func (p ProgressbarPrinter) Start(title ...interface{}) (*ProgressbarPrinter, er
p.updateProgress()
+ if p.ShowElapsedTime {
+ p.rerenderTask = schedule.Every(time.Second, func() bool {
+ p.updateProgress()
+ return true
+ })
+ }
+
return &p, nil
}
// Stop the ProgressbarPrinter.
func (p *ProgressbarPrinter) Stop() (*ProgressbarPrinter, error) {
+ if p.rerenderTask != nil && p.rerenderTask.IsActive() {
+ p.rerenderTask.Stop()
+ }
+ cursor.Show()
+
if !p.IsActive {
return p, nil
}
@@ -291,7 +311,7 @@ func (p *ProgressbarPrinter) Stop() (*ProgressbarPrinter, error) {
// GenericStart runs Start, but returns a LivePrinter.
// This is used for the interface LivePrinter.
// You most likely want to use Start instead of this in your program.
-func (p ProgressbarPrinter) GenericStart() (*LivePrinter, error) {
+func (p *ProgressbarPrinter) GenericStart() (*LivePrinter, error) {
p2, _ := p.Start()
lp := LivePrinter(p2)
return &lp, nil
@@ -300,7 +320,7 @@ func (p ProgressbarPrinter) GenericStart() (*LivePrinter, error) {
// GenericStop runs Stop, but returns a LivePrinter.
// This is used for the interface LivePrinter.
// You most likely want to use Stop instead of this in your program.
-func (p ProgressbarPrinter) GenericStop() (*LivePrinter, error) {
+func (p *ProgressbarPrinter) GenericStop() (*LivePrinter, error) {
p2, _ := p.Stop()
lp := LivePrinter(p2)
return &lp, nil
diff --git a/vendor/github.com/pterm/pterm/pterm.go b/vendor/github.com/pterm/pterm/pterm.go
index be3d9a52..f9d76ca3 100644
--- a/vendor/github.com/pterm/pterm/pterm.go
+++ b/vendor/github.com/pterm/pterm/pterm.go
@@ -6,7 +6,9 @@
// View the animated examples here: https://github.com/pterm/pterm#-examples
package pterm
-import "github.com/gookit/color"
+import (
+ "github.com/gookit/color"
+)
var (
// Output completely disables output from pterm if set to false. Can be used in CLI application quiet mode.
@@ -61,7 +63,7 @@ func DisableStyling() {
DisableColor()
}
-// RecalculateTerminalSize updates already initialized terminal dimensions. Has to be called after a termina resize to guarantee proper rendering. Applies only to new instances.
+// RecalculateTerminalSize updates already initialized terminal dimensions. Has to be called after a terminal resize to guarantee proper rendering. Applies only to new instances.
func RecalculateTerminalSize() {
// keep in sync with DefaultBarChart
DefaultBarChart.Width = GetTerminalWidth() * 2 / 3
diff --git a/vendor/github.com/pterm/pterm/rgb.go b/vendor/github.com/pterm/pterm/rgb.go
index fee602a5..7c00835a 100644
--- a/vendor/github.com/pterm/pterm/rgb.go
+++ b/vendor/github.com/pterm/pterm/rgb.go
@@ -12,9 +12,137 @@ import (
// The name of the model comes from the initials of the three additive primary colors, red, green, and blue.
// https://en.wikipedia.org/wiki/RGB_color_model
type RGB struct {
- R uint8
- G uint8
- B uint8
+ R uint8
+ G uint8
+ B uint8
+ Background bool
+}
+
+type RGBStyle struct {
+ Options []Color
+ Foreground, Background RGB
+
+ hasBg bool
+}
+
+// NewRGBStyle returns a new RGBStyle.
+// The foreground color is required, the background color is optional.
+// The colors will be set as is, ignoring the RGB.Background property.
+func NewRGBStyle(foreground RGB, background ...RGB) RGBStyle {
+ var s RGBStyle
+ s.Foreground = foreground
+ if len(background) > 0 {
+ s.Background = background[0]
+ s.hasBg = true
+ }
+ return s
+}
+
+// AddOptions adds options to the RGBStyle.
+func (p RGBStyle) AddOptions(opts ...Color) RGBStyle {
+ p.Options = append(p.Options, opts...)
+ return p
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p RGBStyle) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p RGBStyle) Println(a ...interface{}) *TextPrinter {
+ Println(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p RGBStyle) Printf(format string, a ...interface{}) *TextPrinter {
+ Printf(format, p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p RGBStyle) Printfln(format string, a ...interface{}) *TextPrinter {
+ Printf(format, p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p RGBStyle) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p RGBStyle) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p RGBStyle) Sprint(a ...interface{}) string {
+ var rgbStyle *color.RGBStyle
+ if !p.hasBg {
+ rgbStyle = color.NewRGBStyle(color.RGB(p.Foreground.R, p.Foreground.G, p.Foreground.B))
+ } else {
+ rgbStyle = color.NewRGBStyle(color.RGB(p.Foreground.R, p.Foreground.G, p.Foreground.B), color.RGB(p.Background.R, p.Background.G, p.Background.B))
+ }
+ if len(p.Options) > 0 {
+ for _, opt := range p.Options {
+ rgbStyle.AddOpts(color.Color(opt))
+ }
+ }
+ return rgbStyle.Sprint(a...)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p RGBStyle) Sprintln(a ...interface{}) string {
+ return p.Sprint(a...) + "\n"
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p RGBStyle) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p RGBStyle) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
}
// GetValues returns the RGB values separately.
@@ -23,12 +151,21 @@ func (p RGB) GetValues() (r, g, b uint8) {
}
// NewRGB returns a new RGB.
-func NewRGB(r, g, b uint8) RGB {
- return RGB{R: r, G: g, B: b}
+func NewRGB(r, g, b uint8, background ...bool) RGB {
+ var bg bool
+
+ if len(background) > 0 {
+ bg = background[0]
+ }
+
+ return RGB{R: r, G: g, B: b, Background: bg}
}
// Fade fades one RGB value (over other RGB values) to another RGB value, by giving the function a minimum, maximum and current value.
func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
+ if max == current {
+ return end[len(end)-1]
+ }
if min < 0 {
max -= min
current -= min
@@ -36,9 +173,10 @@ func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
}
if len(end) == 1 {
return RGB{
- R: uint8(internal.MapRangeToRange(min, max, float32(p.R), float32(end[0].R), current)),
- G: uint8(internal.MapRangeToRange(min, max, float32(p.G), float32(end[0].G), current)),
- B: uint8(internal.MapRangeToRange(min, max, float32(p.B), float32(end[0].B), current)),
+ R: uint8(internal.MapRangeToRange(min, max, float32(p.R), float32(end[0].R), current)),
+ G: uint8(internal.MapRangeToRange(min, max, float32(p.G), float32(end[0].G), current)),
+ B: uint8(internal.MapRangeToRange(min, max, float32(p.B), float32(end[0].B), current)),
+ Background: p.Background,
}
} else if len(end) > 1 {
f := (max - min) / float32(len(end))
@@ -60,7 +198,10 @@ func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
// Sprint formats using the default formats for its operands and returns the resulting string.
// Spaces are added between operands when neither is a string.
func (p RGB) Sprint(a ...interface{}) string {
- return color.RGB(p.R, p.G, p.B).Sprint(a...)
+ if p.Background {
+ return color.RGB(p.R, p.G, p.B, p.Background).Sprint(a...) + "\033[0m\033[K"
+ }
+ return color.RGB(p.R, p.G, p.B, p.Background).Sprint(a...)
}
// Sprintln formats using the default formats for its operands and returns the resulting string.
@@ -146,3 +287,11 @@ func (p RGB) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
tp := TextPrinter(p)
return &tp
}
+
+func (p RGB) ToRGBStyle() RGBStyle {
+ if p.Background {
+ return RGBStyle{Background: p}
+ }
+
+ return RGBStyle{Foreground: p}
+}
diff --git a/vendor/github.com/pterm/pterm/slog_handler.go b/vendor/github.com/pterm/pterm/slog_handler.go
new file mode 100644
index 00000000..a2b2acfe
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/slog_handler.go
@@ -0,0 +1,90 @@
+package pterm
+
+import (
+ "context"
+
+ "log/slog"
+)
+
+type SlogHandler struct {
+ logger *Logger
+ attrs []slog.Attr
+}
+
+// Enabled returns true if the given level is enabled.
+func (s *SlogHandler) Enabled(ctx context.Context, level slog.Level) bool {
+ switch level {
+ case slog.LevelDebug:
+ return s.logger.CanPrint(LogLevelDebug)
+ case slog.LevelInfo:
+ return s.logger.CanPrint(LogLevelInfo)
+ case slog.LevelWarn:
+ return s.logger.CanPrint(LogLevelWarn)
+ case slog.LevelError:
+ return s.logger.CanPrint(LogLevelError)
+ }
+ return false
+}
+
+// Handle handles the given record.
+func (s *SlogHandler) Handle(ctx context.Context, record slog.Record) error {
+ level := record.Level
+ message := record.Message
+
+ // Convert slog Attrs to a map.
+ keyValsMap := make(map[string]interface{})
+
+ record.Attrs(func(attr slog.Attr) bool {
+ keyValsMap[attr.Key] = attr.Value
+ return true
+ })
+
+ for _, attr := range s.attrs {
+ keyValsMap[attr.Key] = attr.Value
+ }
+
+ args := s.logger.ArgsFromMap(keyValsMap)
+
+ // Wrapping args inside another slice to match [][]LoggerArgument
+ argsWrapped := [][]LoggerArgument{args}
+
+ logger := s.logger
+
+ // Must be done here, see https://github.com/pterm/pterm/issues/608#issuecomment-1876001650
+ if logger.CallerOffset == 0 {
+ logger = logger.WithCallerOffset(3)
+ }
+
+ switch level {
+ case slog.LevelDebug:
+ logger.Debug(message, argsWrapped...)
+ case slog.LevelInfo:
+ logger.Info(message, argsWrapped...)
+ case slog.LevelWarn:
+ logger.Warn(message, argsWrapped...)
+ case slog.LevelError:
+ logger.Error(message, argsWrapped...)
+ default:
+ logger.Print(message, argsWrapped...)
+ }
+
+ return nil
+}
+
+// WithAttrs returns a new handler with the given attributes.
+func (s *SlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
+ newS := *s
+ newS.attrs = attrs
+ return &newS
+}
+
+// WithGroup is not yet supported.
+func (s *SlogHandler) WithGroup(name string) slog.Handler {
+ // Grouping is not yet supported by pterm.
+ return s
+}
+
+// NewSlogHandler returns a new logging handler that can be intrgrated with log/slog.
+func NewSlogHandler(logger *Logger) *SlogHandler {
+ return &SlogHandler{logger: logger}
+}
diff --git a/vendor/github.com/pterm/pterm/spinner_printer.go b/vendor/github.com/pterm/pterm/spinner_printer.go
index 86d9c655..044b6976 100644
--- a/vendor/github.com/pterm/pterm/spinner_printer.go
+++ b/vendor/github.com/pterm/pterm/spinner_printer.go
@@ -110,15 +110,18 @@ func (p SpinnerPrinter) WithWriter(writer io.Writer) *SpinnerPrinter {
return &p
}
+// SetWriter sets the custom Writer.
+func (p *SpinnerPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
// UpdateText updates the message of the active SpinnerPrinter.
// Can be used live.
func (s *SpinnerPrinter) UpdateText(text string) {
s.Text = text
if !RawOutput {
- fClearLine(s.Writer)
Fprinto(s.Writer, s.Style.Sprint(s.currentSequence)+" "+s.MessageStyle.Sprint(s.Text))
- }
- if RawOutput {
+ } else {
Fprintln(s.Writer, s.Text)
}
}
@@ -140,7 +143,11 @@ func (s SpinnerPrinter) Start(text ...interface{}) (*SpinnerPrinter, error) {
go func() {
for s.IsActive {
for _, seq := range s.Sequence {
- if !s.IsActive || RawOutput {
+ if !s.IsActive {
+ continue
+ }
+ if RawOutput {
+ time.Sleep(s.Delay)
continue
}
@@ -148,7 +155,6 @@ func (s SpinnerPrinter) Start(text ...interface{}) (*SpinnerPrinter, error) {
if s.ShowTimer {
timer = " (" + time.Since(s.startedAt).Round(s.TimerRoundingFactor).String() + ")"
}
- fClearLine(s.Writer)
Fprinto(s.Writer, s.Style.Sprint(seq)+" "+s.MessageStyle.Sprint(s.Text)+s.TimerStyle.Sprint(timer))
s.currentSequence = seq
time.Sleep(s.Delay)
@@ -178,8 +184,8 @@ func (s *SpinnerPrinter) Stop() error {
// This is used for the interface LivePrinter.
// You most likely want to use Start instead of this in your program.
func (s *SpinnerPrinter) GenericStart() (*LivePrinter, error) {
- _, _ = s.Start()
- lp := LivePrinter(s)
+ p2, _ := s.Start()
+ lp := LivePrinter(p2)
return &lp, nil
}
diff --git a/vendor/github.com/pterm/pterm/table_printer.go b/vendor/github.com/pterm/pterm/table_printer.go
index cbef5019..54e8965a 100644
--- a/vendor/github.com/pterm/pterm/table_printer.go
+++ b/vendor/github.com/pterm/pterm/table_printer.go
@@ -2,9 +2,10 @@ package pterm
import (
"encoding/csv"
- "github.com/pterm/pterm/internal"
"io"
"strings"
+
+ "github.com/pterm/pterm/internal"
)
// DefaultTable contains standards, which can be used to print a TablePrinter.
@@ -183,8 +184,8 @@ func (p TablePrinter) Srender() (string, error) {
c.lines = strings.Split(cRaw, "\n")
c.height = len(c.lines)
for _, l := range c.lines {
- if internal.GetStringMaxWidth(l) > c.width {
- c.width = internal.GetStringMaxWidth(l)
+ if maxWidth := internal.GetStringMaxWidth(l); maxWidth > c.width {
+ c.width = maxWidth
}
}
r.cells = append(r.cells, c)
@@ -262,7 +263,7 @@ func (p TablePrinter) renderRow(t table, r row) string {
}
if i < len(c.lines) {
- s += strings.TrimSpace(c.lines[i])
+ s += c.lines[i]
}
if j < len(r.cells)-1 {
diff --git a/vendor/github.com/pterm/pterm/theme.go b/vendor/github.com/pterm/pterm/theme.go
index 22466ea7..91594c8c 100644
--- a/vendor/github.com/pterm/pterm/theme.go
+++ b/vendor/github.com/pterm/pterm/theme.go
@@ -30,6 +30,9 @@ var (
TableStyle: Style{FgDefault},
TableHeaderStyle: Style{FgLightCyan},
TableSeparatorStyle: Style{FgGray},
+ HeatmapStyle: Style{FgDefault},
+ HeatmapHeaderStyle: Style{FgLightCyan},
+ HeatmapSeparatorStyle: Style{FgDefault},
SectionStyle: Style{Bold, FgYellow},
BulletListTextStyle: Style{FgDefault},
BulletListBulletStyle: Style{FgGray},
@@ -81,6 +84,9 @@ type Theme struct {
TableStyle Style
TableHeaderStyle Style
TableSeparatorStyle Style
+ HeatmapStyle Style
+ HeatmapHeaderStyle Style
+ HeatmapSeparatorStyle Style
SectionStyle Style
BulletListTextStyle Style
BulletListBulletStyle Style
diff --git a/vendor/github.com/pterm/pterm/tree_printer.go b/vendor/github.com/pterm/pterm/tree_printer.go
index fe10c133..113f9202 100644
--- a/vendor/github.com/pterm/pterm/tree_printer.go
+++ b/vendor/github.com/pterm/pterm/tree_printer.go
@@ -124,7 +124,7 @@ func (p TreePrinter) Srender() (string, error) {
var result string
if p.Root.Text != "" {
- result += p.Root.Text + "\n"
+ result += p.TextStyle.Sprint(p.Root.Text) + "\n"
}
result += walkOverTree(p.Root.Children, p, "")
return result, nil
diff --git a/vendor/github.com/sheldonhull/magetools/ci/ci.go b/vendor/github.com/sheldonhull/magetools/ci/ci.go
index 670dadcb..162c3f79 100644
--- a/vendor/github.com/sheldonhull/magetools/ci/ci.go
+++ b/vendor/github.com/sheldonhull/magetools/ci/ci.go
@@ -16,19 +16,35 @@ import (
// IsCI will set the global variable for IsCI based on lookup of the environment variable.
func IsCI() bool {
magetoolsutils.CheckPtermDebug()
+
_, exists := os.LookupEnv("AGENT_ID")
if exists {
pterm.Info.Println("Azure DevOps match based on AGENT_ID. Setting IS_CI = 1")
return true
}
+ _, exists = os.LookupEnv("GITLAB_CI")
+ if exists {
+ pterm.Info.Println("Gitlab Runner match based on [GITLAB_CI] env variable. Setting IS_CI = 1")
+
+ return true
+ }
+
_, exists = os.LookupEnv("NETLIFY")
if exists {
pterm.Info.Println("Netlify match based on [NETLIFY] environment. Setting IS_CI = 1")
return true
}
+ _, exists = os.LookupEnv("GITHUB_ACTIONS")
+ if exists {
+ pterm.Info.Println("GitHub Actions match based on [GITHUB_ACTIONS] environment. Setting IS_CI = 1")
+
+ return true
+ }
+
// CI is also set for Netlify, so it's important to run the NETFLIFY check before the CI check.
+ // It might be used by others since it's so common so let's leave this check to the very end.
_, exists = os.LookupEnv("CI")
if exists {
pterm.Info.Println("GitHub actions match based on [CI] env variable. Setting IS_CI = 1")
diff --git a/vendor/github.com/sheldonhull/magetools/gotools/gotools.go b/vendor/github.com/sheldonhull/magetools/gotools/gotools.go
index f952722b..3bf5cc17 100644
--- a/vendor/github.com/sheldonhull/magetools/gotools/gotools.go
+++ b/vendor/github.com/sheldonhull/magetools/gotools/gotools.go
@@ -270,7 +270,7 @@ func (Go) Lint() error {
Printfln("unable to find %s: %v", appgolangcilint, err)
return err
}
- pterm.Info.Printfln("gotestsum found: %s", golangcilint)
+ pterm.Info.Printfln("golangci-lint found: %s", golangcilint)
if err := sh.RunV(golangcilint, "run"); err != nil {
pterm.Error.WithShowLineNumber(true).WithLineNumberOffset(1).Println("golangci-lint failure")
diff --git a/vendor/github.com/sheldonhull/magetools/pkg/magetoolsutils/magetoolsutils.go b/vendor/github.com/sheldonhull/magetools/pkg/magetoolsutils/magetoolsutils.go
index 20b6762b..ca60bfe7 100644
--- a/vendor/github.com/sheldonhull/magetools/pkg/magetoolsutils/magetoolsutils.go
+++ b/vendor/github.com/sheldonhull/magetools/pkg/magetoolsutils/magetoolsutils.go
@@ -32,7 +32,7 @@ func CheckPtermDebug() { //nolint:cyclop,funlen // cyclop,funlen: i'm sure there
}
if debug {
pterm.Debug.Println("strconv.ParseBool(\"DEBUG\") true, enabling debug output and exiting")
- pterm.Info.Println("DEBUG env var detected, setting tasks to debug level output")
+ pterm.Debug.Println("DEBUG env var detected, setting tasks to debug level output")
pterm.EnableDebugMessages()
return
}
@@ -50,7 +50,7 @@ func CheckPtermDebug() { //nolint:cyclop,funlen // cyclop,funlen: i'm sure there
if debug {
pterm.Debug.Println("strconv.ParseBool(\"SYSTEM_DEBUG\") true, enabling debug output and exiting")
- pterm.Info.Println("SYSTEM_DEBUG env var detected, setting tasks to debug level output")
+ pterm.Debug.Println("SYSTEM_DEBUG env var detected, setting tasks to debug level output")
pterm.EnableDebugMessages()
return
}
@@ -74,7 +74,7 @@ func CheckPtermDebug() { //nolint:cyclop,funlen // cyclop,funlen: i'm sure there
}
if mg.Verbose() {
pterm.Debug.Printfln("mg.Verbose() true, setting pterm.EnableDebugMessages()")
- pterm.Info.Println("mg.Verbose() true (-v or MAGEFILE_VERBOSE env var), setting tasks to debug level output")
+ pterm.Debug.Println("mg.Verbose() true (-v or MAGEFILE_VERBOSE env var), setting tasks to debug level output")
pterm.EnableDebugMessages()
return
}
diff --git a/vendor/github.com/ztrue/tracerr/.travis.yml b/vendor/github.com/ztrue/tracerr/.travis.yml
index 6fa4d856..6e20d5cd 100644
--- a/vendor/github.com/ztrue/tracerr/.travis.yml
+++ b/vendor/github.com/ztrue/tracerr/.travis.yml
@@ -1,7 +1,6 @@
language: go
before_install:
- - go get github.com/logrusorgru/aurora
- go get github.com/mattn/goveralls
go:
diff --git a/vendor/github.com/ztrue/tracerr/CHANGELOG.md b/vendor/github.com/ztrue/tracerr/CHANGELOG.md
index b8560c97..7a8a2a84 100644
--- a/vendor/github.com/ztrue/tracerr/CHANGELOG.md
+++ b/vendor/github.com/ztrue/tracerr/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [0.4.0] - 2023-05-21
+
+### Changed
+
+- `github.com/logrusorgru/aurora` dependency removed.
+- Deprecated `ioutil.ReadFile` replaced with `os.ReadFile`.
+
## [0.3.0] - 2019-03-15
### Added
diff --git a/vendor/github.com/ztrue/tracerr/colors.go b/vendor/github.com/ztrue/tracerr/colors.go
new file mode 100644
index 00000000..c96999e9
--- /dev/null
+++ b/vendor/github.com/ztrue/tracerr/colors.go
@@ -0,0 +1,27 @@
+package tracerr
+
+import (
+ "fmt"
+)
+
+// Colorize outputs using [ANSI Escape Codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
+
+func color(code int, in string) string {
+ return fmt.Sprintf("\x1b[%dm%s\x1b[0m", code, in)
+}
+
+func bold(in string) string {
+ return color(1, in)
+}
+
+func black(in string) string {
+ return color(30, in)
+}
+
+func red(in string) string {
+ return color(31, in)
+}
+
+func yellow(in string) string {
+ return color(33, in)
+}
diff --git a/vendor/github.com/ztrue/tracerr/print.go b/vendor/github.com/ztrue/tracerr/print.go
index 2249ace6..c6d36406 100644
--- a/vendor/github.com/ztrue/tracerr/print.go
+++ b/vendor/github.com/ztrue/tracerr/print.go
@@ -2,11 +2,10 @@ package tracerr
import (
"fmt"
- "io/ioutil"
+ "os"
+ "strconv"
"strings"
"sync"
-
- "github.com/logrusorgru/aurora"
)
// DefaultLinesAfter is number of source lines after traced line to display.
@@ -26,7 +25,7 @@ func Print(err error) {
// PrintSource prints error message with stack trace and source fragments.
//
-// By default 6 lines of source code will be printed,
+// By default, 6 lines of source code will be printed,
// see DefaultLinesAfter and DefaultLinesBefore.
//
// Pass a single number to specify a total number of source lines.
@@ -95,7 +94,7 @@ func readLines(path string) ([]string, error) {
return lines, nil
}
- b, err := ioutil.ReadFile(path)
+ b, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("tracerr: file %s not found", path)
}
@@ -111,7 +110,7 @@ func sourceRows(rows []string, frame Frame, before, after int, colorized bool) [
if err != nil {
message := err.Error()
if colorized {
- message = aurora.Brown(message).String()
+ message = yellow(message)
}
return append(rows, message, "")
}
@@ -121,7 +120,7 @@ func sourceRows(rows []string, frame Frame, before, after int, colorized bool) [
len(lines), frame.Line,
)
if colorized {
- message = aurora.Brown(message).String()
+ message = yellow(message)
}
return append(rows, message, "")
}
@@ -136,14 +135,14 @@ func sourceRows(rows []string, frame Frame, before, after int, colorized bool) [
var message string
// TODO Pad to the same length.
if i == frame.Line-1 {
- message = fmt.Sprintf("%d\t%s", i+1, string(line))
+ message = fmt.Sprintf("%d\t%s", i+1, line)
if colorized {
- message = aurora.Red(message).String()
+ message = red(message)
}
} else if colorized {
- message = aurora.Sprintf("%d\t%s", aurora.Black(i+1), string(line))
+ message = fmt.Sprintf("%s\t%s", black(strconv.Itoa(i+1)), line)
} else {
- message = fmt.Sprintf("%d\t%s", i+1, string(line))
+ message = fmt.Sprintf("%d\t%s", i+1, line)
}
rows = append(rows, message)
}
@@ -172,7 +171,7 @@ func sprint(err error, nums []int, colorized bool) string {
for _, frame := range frames {
message := frame.String()
if colorized {
- message = aurora.Bold(message).String()
+ message = bold(message)
}
rows = append(rows, message)
if withSource {
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 6202638b..c6492020 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -248,6 +248,7 @@ struct ltchars {
#include
#include
#include
+#include
#include
#include
#include
@@ -283,10 +284,6 @@ struct ltchars {
#include
#endif
-#ifndef MSG_FASTOPEN
-#define MSG_FASTOPEN 0x20000000
-#endif
-
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc
#endif
@@ -295,14 +292,6 @@ struct ltchars {
#define PTRACE_SETREGS 0xd
#endif
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-#ifndef SOL_SMC
-#define SOL_SMC 286
-#endif
-
#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
@@ -319,10 +308,23 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff
-// Copied from linux/l2tp.h
-// Including linux/l2tp.h here causes conflicts between linux/in.h
-// and netinet/in.h included via net/route.h above.
-#define IPPROTO_L2TP 115
+// Copied from linux/netfilter/nf_nat.h
+// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
+// and netinet/in.h.
+#define NF_NAT_RANGE_MAP_IPS (1 << 0)
+#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
+#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
+#define NF_NAT_RANGE_PERSISTENT (1 << 3)
+#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
+#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
+ (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+#define NF_NAT_RANGE_MASK \
+ (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
+ NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields.
@@ -603,6 +605,9 @@ ccflags="$@"
$2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ ||
+ $2 !~ /^NFT_META_IIFTYPE/ &&
+ $2 ~ /^NFT_/ ||
+ $2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ ||
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index c73cfe2f..a5d3ff8d 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -2127,6 +2127,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969
+ NFT_CHAIN_FLAGS = 0x7
+ NFT_CHAIN_MAXNAMELEN = 0x100
+ NFT_CT_MAX = 0x17
+ NFT_DATA_RESERVED_MASK = 0xffffff00
+ NFT_DATA_VALUE_MAXLEN = 0x40
+ NFT_EXTHDR_OP_MAX = 0x4
+ NFT_FIB_RESULT_MAX = 0x3
+ NFT_INNER_MASK = 0xf
+ NFT_LOGLEVEL_MAX = 0x8
+ NFT_NAME_MAXLEN = 0x100
+ NFT_NG_MAX = 0x1
+ NFT_OBJECT_CONNLIMIT = 0x5
+ NFT_OBJECT_COUNTER = 0x1
+ NFT_OBJECT_CT_EXPECT = 0x9
+ NFT_OBJECT_CT_HELPER = 0x3
+ NFT_OBJECT_CT_TIMEOUT = 0x7
+ NFT_OBJECT_LIMIT = 0x4
+ NFT_OBJECT_MAX = 0xa
+ NFT_OBJECT_QUOTA = 0x2
+ NFT_OBJECT_SECMARK = 0x8
+ NFT_OBJECT_SYNPROXY = 0xa
+ NFT_OBJECT_TUNNEL = 0x6
+ NFT_OBJECT_UNSPEC = 0x0
+ NFT_OBJ_MAXNAMELEN = 0x100
+ NFT_OSF_MAXGENRELEN = 0x10
+ NFT_QUEUE_FLAG_BYPASS = 0x1
+ NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
+ NFT_QUEUE_FLAG_MASK = 0x3
+ NFT_REG32_COUNT = 0x10
+ NFT_REG32_SIZE = 0x4
+ NFT_REG_MAX = 0x4
+ NFT_REG_SIZE = 0x10
+ NFT_REJECT_ICMPX_MAX = 0x3
+ NFT_RT_MAX = 0x4
+ NFT_SECMARK_CTX_MAXLEN = 0x100
+ NFT_SET_MAXNAMELEN = 0x100
+ NFT_SOCKET_MAX = 0x3
+ NFT_TABLE_F_MASK = 0x3
+ NFT_TABLE_MAXNAMELEN = 0x100
+ NFT_TRACETYPE_MAX = 0x3
+ NFT_TUNNEL_F_MASK = 0x7
+ NFT_TUNNEL_MAX = 0x1
+ NFT_TUNNEL_MODE_MAX = 0x2
+ NFT_USERDATA_MAXLEN = 0x100
+ NFT_XFRM_KEY_MAX = 0x6
+ NF_NAT_RANGE_MAP_IPS = 0x1
+ NF_NAT_RANGE_MASK = 0x7f
+ NF_NAT_RANGE_NETMAP = 0x40
+ NF_NAT_RANGE_PERSISTENT = 0x8
+ NF_NAT_RANGE_PROTO_OFFSET = 0x20
+ NF_NAT_RANGE_PROTO_RANDOM = 0x4
+ NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
+ NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0
NL1 = 0x100
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
index a1d06159..9dc42410 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
index 5b2a7409..0d3a0751 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
index f6eda134..c39f7776 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
index 55df20ae..57571d07 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
index 8c1155cb..e62963e6 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
index 7cc80c58..00831354 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
index 0688737f..79029ed5 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 47dc5796..ffb8708c 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error)
+//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 146a1f01..e8791c82 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent")
@@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
return
}
+func SetFileValidData(handle Handle, validDataLength int64) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 28f7f292..af441119 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,4 +1,4 @@
-# atomicgo.dev/cursor v0.1.1
+# atomicgo.dev/cursor v0.2.0
## explicit; go 1.15
atomicgo.dev/cursor
# atomicgo.dev/keyboard v0.2.9
@@ -6,9 +6,9 @@ atomicgo.dev/cursor
atomicgo.dev/keyboard
atomicgo.dev/keyboard/internal
atomicgo.dev/keyboard/keys
-# bitbucket.org/creachadair/shell v0.0.7
-## explicit; go 1.16
-bitbucket.org/creachadair/shell
+# atomicgo.dev/schedule v0.1.0
+## explicit; go 1.18
+atomicgo.dev/schedule
# cloud.google.com/go v0.110.0
## explicit; go 1.19
cloud.google.com/go/internal
@@ -31,7 +31,7 @@ cloud.google.com/go/storage
cloud.google.com/go/storage/internal
cloud.google.com/go/storage/internal/apiv2
cloud.google.com/go/storage/internal/apiv2/stubs
-# github.com/DelineaXPM/dsv-sdk-go/v2 v2.0.1-0.20220719195420-2376a5c350ab
+# github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.0
## explicit; go 1.18
github.com/DelineaXPM/dsv-sdk-go/v2/auth
github.com/DelineaXPM/dsv-sdk-go/v2/vault
@@ -113,14 +113,14 @@ github.com/bgentry/go-netrc/netrc
# github.com/bgentry/speakeasy v0.1.0
## explicit
github.com/bgentry/speakeasy
-# github.com/bitfield/script v0.20.2
+# github.com/bitfield/script v0.22.0
## explicit; go 1.12
github.com/bitfield/script
# github.com/containerd/console v1.0.3
## explicit; go 1.13
github.com/containerd/console
-# github.com/dustin/go-humanize v1.0.0
-## explicit
+# github.com/dustin/go-humanize v1.0.1
+## explicit; go 1.16
github.com/dustin/go-humanize
# github.com/fatih/color v1.13.0
## explicit; go 1.13
@@ -157,8 +157,8 @@ github.com/googleapis/gax-go/v2
github.com/googleapis/gax-go/v2/apierror
github.com/googleapis/gax-go/v2/apierror/internal/proto
github.com/googleapis/gax-go/v2/internal
-# github.com/gookit/color v1.5.2
-## explicit; go 1.16
+# github.com/gookit/color v1.5.4
+## explicit; go 1.18
github.com/gookit/color
# github.com/hashicorp/errwrap v1.1.0
## explicit
@@ -249,11 +249,11 @@ github.com/huandu/xstrings
# github.com/imdario/mergo v0.3.13
## explicit; go 1.13
github.com/imdario/mergo
-# github.com/itchyny/gojq v0.12.7
-## explicit; go 1.16
+# github.com/itchyny/gojq v0.12.12
+## explicit; go 1.18
github.com/itchyny/gojq
-# github.com/itchyny/timefmt-go v0.1.3
-## explicit; go 1.14
+# github.com/itchyny/timefmt-go v0.1.5
+## explicit; go 1.17
github.com/itchyny/timefmt-go
# github.com/jmespath/go-jmespath v0.4.0
## explicit; go 1.14
@@ -267,23 +267,20 @@ github.com/klauspost/compress/internal/cpuinfo
github.com/klauspost/compress/internal/snapref
github.com/klauspost/compress/zstd
github.com/klauspost/compress/zstd/internal/xxhash
-# github.com/lithammer/fuzzysearch v1.1.5
+# github.com/lithammer/fuzzysearch v1.1.8
## explicit; go 1.15
github.com/lithammer/fuzzysearch/fuzzy
-# github.com/logrusorgru/aurora v2.0.3+incompatible
-## explicit
-github.com/logrusorgru/aurora
-# github.com/magefile/mage v1.14.0
+# github.com/magefile/mage v1.15.0
## explicit; go 1.12
github.com/magefile/mage/mg
github.com/magefile/mage/sh
# github.com/mattn/go-colorable v0.1.13
## explicit; go 1.15
github.com/mattn/go-colorable
-# github.com/mattn/go-isatty v0.0.16
+# github.com/mattn/go-isatty v0.0.17
## explicit; go 1.15
github.com/mattn/go-isatty
-# github.com/mattn/go-runewidth v0.0.14
+# github.com/mattn/go-runewidth v0.0.15
## explicit; go 1.9
github.com/mattn/go-runewidth
# github.com/mitchellh/cli v1.1.4
@@ -315,14 +312,14 @@ github.com/oklog/run
github.com/posener/complete
github.com/posener/complete/cmd
github.com/posener/complete/cmd/install
-# github.com/pterm/pterm v0.12.56
-## explicit; go 1.18
+# github.com/pterm/pterm v0.12.76
+## explicit; go 1.21
github.com/pterm/pterm
github.com/pterm/pterm/internal
# github.com/rivo/uniseg v0.4.4
## explicit; go 1.18
github.com/rivo/uniseg
-# github.com/sheldonhull/magetools v1.0.0
+# github.com/sheldonhull/magetools v1.0.1
## explicit; go 1.18
github.com/sheldonhull/magetools/ci
github.com/sheldonhull/magetools/gotools
@@ -371,7 +368,7 @@ github.com/zclconf/go-cty/cty/set
# github.com/zclconf/go-cty-yaml v1.0.2
## explicit
github.com/zclconf/go-cty-yaml
-# github.com/ztrue/tracerr v0.3.0
+# github.com/ztrue/tracerr v0.4.0
## explicit
github.com/ztrue/tracerr
# go.opencensus.io v0.24.0
@@ -406,7 +403,7 @@ golang.org/x/crypto/openpgp/packet
golang.org/x/crypto/openpgp/s2k
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/scrypt
-# golang.org/x/mod v0.8.0
+# golang.org/x/mod v0.10.0
## explicit; go 1.17
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -430,12 +427,12 @@ golang.org/x/oauth2/google/internal/externalaccount
golang.org/x/oauth2/internal
golang.org/x/oauth2/jws
golang.org/x/oauth2/jwt
-# golang.org/x/sys v0.15.0
+# golang.org/x/sys v0.16.0
## explicit; go 1.18
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/term v0.15.0
+# golang.org/x/term v0.16.0
## explicit; go 1.18
golang.org/x/term
# golang.org/x/text v0.14.0
@@ -602,3 +599,10 @@ google.golang.org/protobuf/types/known/durationpb
google.golang.org/protobuf/types/known/emptypb
google.golang.org/protobuf/types/known/fieldmaskpb
google.golang.org/protobuf/types/known/timestamppb
+# mvdan.cc/sh/v3 v3.6.0
+## explicit; go 1.18
+mvdan.cc/sh/v3/expand
+mvdan.cc/sh/v3/fileutil
+mvdan.cc/sh/v3/pattern
+mvdan.cc/sh/v3/shell
+mvdan.cc/sh/v3/syntax
diff --git a/vendor/mvdan.cc/sh/v3/LICENSE b/vendor/mvdan.cc/sh/v3/LICENSE
new file mode 100644
index 00000000..2a5268e5
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2016, Daniel Martí. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/mvdan.cc/sh/v3/expand/arith.go b/vendor/mvdan.cc/sh/v3/expand/arith.go
new file mode 100644
index 00000000..3ce199ec
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/arith.go
@@ -0,0 +1,221 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+package expand
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "mvdan.cc/sh/v3/syntax"
+)
+
+func Arithm(cfg *Config, expr syntax.ArithmExpr) (int, error) {
+ switch x := expr.(type) {
+ case *syntax.Word:
+ str, err := Literal(cfg, x)
+ if err != nil {
+ return 0, err
+ }
+ // recursively fetch vars
+ i := 0
+ for syntax.ValidName(str) {
+ val := cfg.envGet(str)
+ if val == "" {
+ break
+ }
+ if i++; i >= maxNameRefDepth {
+ break
+ }
+ str = val
+ }
+ // default to 0
+ return atoi(str), nil
+ case *syntax.ParenArithm:
+ return Arithm(cfg, x.X)
+ case *syntax.UnaryArithm:
+ switch x.Op {
+ case syntax.Inc, syntax.Dec:
+ name := x.X.(*syntax.Word).Lit()
+ old := atoi(cfg.envGet(name))
+ val := old
+ if x.Op == syntax.Inc {
+ val++
+ } else {
+ val--
+ }
+ if err := cfg.envSet(name, strconv.Itoa(val)); err != nil {
+ return 0, err
+ }
+ if x.Post {
+ return old, nil
+ }
+ return val, nil
+ }
+ val, err := Arithm(cfg, x.X)
+ if err != nil {
+ return 0, err
+ }
+ switch x.Op {
+ case syntax.Not:
+ return oneIf(val == 0), nil
+ case syntax.BitNegation:
+ return ^val, nil
+ case syntax.Plus:
+ return val, nil
+ default: // syntax.Minus
+ return -val, nil
+ }
+ case *syntax.BinaryArithm:
+ switch x.Op {
+ case syntax.Assgn, syntax.AddAssgn, syntax.SubAssgn,
+ syntax.MulAssgn, syntax.QuoAssgn, syntax.RemAssgn,
+ syntax.AndAssgn, syntax.OrAssgn, syntax.XorAssgn,
+ syntax.ShlAssgn, syntax.ShrAssgn:
+ return cfg.assgnArit(x)
+ case syntax.TernQuest: // TernColon can't happen here
+ cond, err := Arithm(cfg, x.X)
+ if err != nil {
+ return 0, err
+ }
+ b2 := x.Y.(*syntax.BinaryArithm) // must have Op==TernColon
+ if cond == 1 {
+ return Arithm(cfg, b2.X)
+ }
+ return Arithm(cfg, b2.Y)
+ }
+ left, err := Arithm(cfg, x.X)
+ if err != nil {
+ return 0, err
+ }
+ right, err := Arithm(cfg, x.Y)
+ if err != nil {
+ return 0, err
+ }
+ return binArit(x.Op, left, right)
+ default:
+ panic(fmt.Sprintf("unexpected arithm expr: %T", x))
+ }
+}
+
+func oneIf(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+// atoi is like strconv.Atoi, but it ignores errors and trims whitespace.
+func atoi(s string) int {
+ s = strings.TrimSpace(s)
+ n, _ := strconv.Atoi(s)
+ return n
+}
+
+func (cfg *Config) assgnArit(b *syntax.BinaryArithm) (int, error) {
+ name := b.X.(*syntax.Word).Lit()
+ val := atoi(cfg.envGet(name))
+ arg, err := Arithm(cfg, b.Y)
+ if err != nil {
+ return 0, err
+ }
+ switch b.Op {
+ case syntax.Assgn:
+ val = arg
+ case syntax.AddAssgn:
+ val += arg
+ case syntax.SubAssgn:
+ val -= arg
+ case syntax.MulAssgn:
+ val *= arg
+ case syntax.QuoAssgn:
+ if arg == 0 {
+ return 0, fmt.Errorf("division by zero")
+ }
+ val /= arg
+ case syntax.RemAssgn:
+ if arg == 0 {
+ return 0, fmt.Errorf("division by zero")
+ }
+ val %= arg
+ case syntax.AndAssgn:
+ val &= arg
+ case syntax.OrAssgn:
+ val |= arg
+ case syntax.XorAssgn:
+ val ^= arg
+ case syntax.ShlAssgn:
+ val <<= uint(arg)
+ case syntax.ShrAssgn:
+ val >>= uint(arg)
+ }
+ if err := cfg.envSet(name, strconv.Itoa(val)); err != nil {
+ return 0, err
+ }
+ return val, nil
+}
+
+func intPow(a, b int) int {
+ p := 1
+ for b > 0 {
+ if b&1 != 0 {
+ p *= a
+ }
+ b >>= 1
+ a *= a
+ }
+ return p
+}
+
+func binArit(op syntax.BinAritOperator, x, y int) (int, error) {
+ switch op {
+ case syntax.Add:
+ return x + y, nil
+ case syntax.Sub:
+ return x - y, nil
+ case syntax.Mul:
+ return x * y, nil
+ case syntax.Quo:
+ if y == 0 {
+ return 0, fmt.Errorf("division by zero")
+ }
+ return x / y, nil
+ case syntax.Rem:
+ if y == 0 {
+ return 0, fmt.Errorf("division by zero")
+ }
+ return x % y, nil
+ case syntax.Pow:
+ return intPow(x, y), nil
+ case syntax.Eql:
+ return oneIf(x == y), nil
+ case syntax.Gtr:
+ return oneIf(x > y), nil
+ case syntax.Lss:
+ return oneIf(x < y), nil
+ case syntax.Neq:
+ return oneIf(x != y), nil
+ case syntax.Leq:
+ return oneIf(x <= y), nil
+ case syntax.Geq:
+ return oneIf(x >= y), nil
+ case syntax.And:
+ return x & y, nil
+ case syntax.Or:
+ return x | y, nil
+ case syntax.Xor:
+ return x ^ y, nil
+ case syntax.Shr:
+ return x >> uint(y), nil
+ case syntax.Shl:
+ return x << uint(y), nil
+ case syntax.AndArit:
+ return oneIf(x != 0 && y != 0), nil
+ case syntax.OrArit:
+ return oneIf(x != 0 || y != 0), nil
+ default: // syntax.Comma
+ // x is executed but its result discarded
+ return y, nil
+ }
+}
diff --git a/vendor/mvdan.cc/sh/v3/expand/braces.go b/vendor/mvdan.cc/sh/v3/expand/braces.go
new file mode 100644
index 00000000..e0363aa2
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/braces.go
@@ -0,0 +1,85 @@
+// Copyright (c) 2018, Daniel Martí
+// See LICENSE for licensing information
+
+package expand
+
+import (
+ "strconv"
+
+ "mvdan.cc/sh/v3/syntax"
+)
+
+// Braces performs brace expansion on a word, given that it contains any
+// syntax.BraceExp parts. For example, the word with a brace expansion
+// "foo{bar,baz}" will return two literal words, "foobar" and "foobaz".
+//
+// Note that the resulting words may share word parts.
+func Braces(word *syntax.Word) []*syntax.Word {
+ var all []*syntax.Word
+ var left []syntax.WordPart
+ for i, wp := range word.Parts {
+ br, ok := wp.(*syntax.BraceExp)
+ if !ok {
+ left = append(left, wp)
+ continue
+ }
+ if br.Sequence {
+ chars := false
+ from, err1 := strconv.Atoi(br.Elems[0].Lit())
+ to, err2 := strconv.Atoi(br.Elems[1].Lit())
+ if err1 != nil || err2 != nil {
+ chars = true
+ from = int(br.Elems[0].Lit()[0])
+ to = int(br.Elems[1].Lit()[0])
+ }
+ upward := from <= to
+ incr := 1
+ if !upward {
+ incr = -1
+ }
+ if len(br.Elems) > 2 {
+ n, _ := strconv.Atoi(br.Elems[2].Lit())
+ if n != 0 && n > 0 == upward {
+ incr = n
+ }
+ }
+ n := from
+ for {
+ if upward && n > to {
+ break
+ }
+ if !upward && n < to {
+ break
+ }
+ next := *word
+ next.Parts = next.Parts[i+1:]
+ lit := &syntax.Lit{}
+ if chars {
+ lit.Value = string(rune(n))
+ } else {
+ lit.Value = strconv.Itoa(n)
+ }
+ next.Parts = append([]syntax.WordPart{lit}, next.Parts...)
+ exp := Braces(&next)
+ for _, w := range exp {
+ w.Parts = append(left, w.Parts...)
+ }
+ all = append(all, exp...)
+ n += incr
+ }
+ return all
+ }
+ for _, elem := range br.Elems {
+ next := *word
+ next.Parts = next.Parts[i+1:]
+ next.Parts = append(elem.Parts, next.Parts...)
+ exp := Braces(&next)
+ for _, w := range exp {
+ w.Parts = append(left, w.Parts...)
+ }
+ all = append(all, exp...)
+ }
+ return all
+ }
+ return []*syntax.Word{{Parts: left}}
+}
diff --git a/vendor/mvdan.cc/sh/v3/expand/doc.go b/vendor/mvdan.cc/sh/v3/expand/doc.go
new file mode 100644
index 00000000..19d95180
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/doc.go
@@ -0,0 +1,5 @@
+// Copyright (c) 2018, Daniel Martí
+// See LICENSE for licensing information
+
+// Package expand contains code to perform various shell expansions.
+package expand
diff --git a/vendor/mvdan.cc/sh/v3/expand/environ.go b/vendor/mvdan.cc/sh/v3/expand/environ.go
new file mode 100644
index 00000000..68ba384e
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/environ.go
@@ -0,0 +1,227 @@
+// Copyright (c) 2018, Daniel Martí
+// See LICENSE for licensing information
+
+package expand
+
+import (
+ "runtime"
+ "sort"
+ "strings"
+)
+
+// Environ is the base interface for a shell's environment, allowing it to fetch
+// variables by name and to iterate over all the currently set variables.
+type Environ interface {
+ // Get retrieves a variable by its name. To check if the variable is
+ // set, use Variable.IsSet.
+ Get(name string) Variable
+
+ // Each iterates over all the currently set variables, calling the
+ // supplied function on each variable. Iteration is stopped if the
+ // function returns false.
+ //
+ // The names used in the calls aren't required to be unique or sorted.
+ // If a variable name appears twice, the latest occurrence takes
+ // priority.
+ //
+ // Each is required to forward exported variables when executing
+ // programs.
+ Each(func(name string, vr Variable) bool)
+}
+
+// WriteEnviron is an extension on Environ that supports modifying and deleting
+// variables.
+type WriteEnviron interface {
+ Environ
+ // Set sets a variable by name. If !vr.IsSet(), the variable is being
+ // unset; otherwise, the variable is being replaced.
+ //
+ // It is the implementation's responsibility to handle variable
+ // attributes correctly. For example, changing an exported variable's
+ // value does not unexport it, and overwriting a name reference variable
+ // should modify its target.
+ //
+ // An error may be returned if the operation is invalid, such as if the
+ // name is empty or if we're trying to overwrite a read-only variable.
+ Set(name string, vr Variable) error
+}
+
+type ValueKind uint8
+
+const (
+ Unset ValueKind = iota
+ String
+ NameRef
+ Indexed
+ Associative
+)
+
+// Variable describes a shell variable, which can have a number of attributes
+// and a value.
+//
+// A Variable is unset if its Kind field is Unset, which can be checked via
+// Variable.IsSet. The zero value of a Variable is thus a valid unset variable.
+//
+// If a variable is set, its Value field will be a []string if it is an indexed
+// array, a map[string]string if it's an associative array, or a string
+// otherwise.
+type Variable struct {
+ Local bool
+ Exported bool
+ ReadOnly bool
+
+ Kind ValueKind
+
+ Str string // Used when Kind is String or NameRef.
+ List []string // Used when Kind is Indexed.
+ Map map[string]string // Used when Kind is Associative.
+}
+
+// IsSet returns whether the variable is set. An empty variable is set, but an
+// undeclared variable is not.
+func (v Variable) IsSet() bool {
+ return v.Kind != Unset
+}
+
+// String returns the variable's value as a string. In general, this only makes
+// sense if the variable has a string value or no value at all.
+func (v Variable) String() string {
+ switch v.Kind {
+ case String:
+ return v.Str
+ case Indexed:
+ if len(v.List) > 0 {
+ return v.List[0]
+ }
+ case Associative:
+ // nothing to do
+ }
+ return ""
+}
+
+// maxNameRefDepth defines the maximum number of times to follow references when
+// resolving a variable. Otherwise, simple name reference loops could crash a
+// program quite easily.
+const maxNameRefDepth = 100
+
+// Resolve follows a number of nameref variables, returning the last reference
+// name that was followed and the variable that it points to.
+func (v Variable) Resolve(env Environ) (string, Variable) {
+ name := ""
+ for i := 0; i < maxNameRefDepth; i++ {
+ if v.Kind != NameRef {
+ return name, v
+ }
+ name = v.Str // keep name for the next iteration
+ v = env.Get(name)
+ }
+ return name, Variable{}
+}
+
+// FuncEnviron wraps a function mapping variable names to their string values,
+// and implements Environ. Empty strings returned by the function will be
+// treated as unset variables. All variables will be exported.
+//
+// Note that the returned Environ's Each method will be a no-op.
+func FuncEnviron(fn func(string) string) Environ {
+ return funcEnviron(fn)
+}
+
+type funcEnviron func(string) string
+
+func (f funcEnviron) Get(name string) Variable {
+ value := f(name)
+ if value == "" {
+ return Variable{}
+ }
+ return Variable{Exported: true, Kind: String, Str: value}
+}
+
+func (f funcEnviron) Each(func(name string, vr Variable) bool) {}
+
+// ListEnviron returns an Environ with the supplied variables, in the form
+// "key=value". All variables will be exported. The last value in pairs is used
+// if multiple values are present.
+//
+// On Windows, where environment variable names are case-insensitive, the
+// resulting variable names will all be uppercase.
+func ListEnviron(pairs ...string) Environ {
+ return listEnvironWithUpper(runtime.GOOS == "windows", pairs...)
+}
+
+// listEnvironWithUpper implements ListEnviron, but letting the tests specify
+// whether to uppercase all names or not.
+func listEnvironWithUpper(upper bool, pairs ...string) Environ {
+ list := append([]string{}, pairs...)
+ if upper {
+ // Uppercase before sorting, so that we can remove duplicates
+ // without the need for linear search nor a map.
+ for i, s := range list {
+ if sep := strings.IndexByte(s, '='); sep > 0 {
+ list[i] = strings.ToUpper(s[:sep]) + s[sep:]
+ }
+ }
+ }
+
+ sort.SliceStable(list, func(i, j int) bool {
+ isep := strings.IndexByte(list[i], '=')
+ jsep := strings.IndexByte(list[j], '=')
+ if isep < 0 {
+ isep = 0
+ } else {
+ isep += 1
+ }
+ if jsep < 0 {
+ jsep = 0
+ } else {
+ jsep += 1
+ }
+ return list[i][:isep] < list[j][:jsep]
+ })
+
+ last := ""
+ for i := 0; i < len(list); {
+ s := list[i]
+ sep := strings.IndexByte(s, '=')
+ if sep <= 0 {
+ // invalid element; remove it
+ list = append(list[:i], list[i+1:]...)
+ continue
+ }
+ name := s[:sep]
+ if last == name {
+ // duplicate; the last one wins
+ list = append(list[:i-1], list[i:]...)
+ continue
+ }
+ last = name
+ i++
+ }
+ return listEnviron(list)
+}
+
+// listEnviron is a sorted list of "name=value" strings.
+type listEnviron []string
+
+func (l listEnviron) Get(name string) Variable {
+ prefix := name + "="
+ i := sort.SearchStrings(l, prefix)
+ if i < len(l) && strings.HasPrefix(l[i], prefix) {
+ return Variable{Exported: true, Kind: String, Str: strings.TrimPrefix(l[i], prefix)}
+ }
+ return Variable{}
+}
+
+func (l listEnviron) Each(fn func(name string, vr Variable) bool) {
+ for _, pair := range l {
+ i := strings.IndexByte(pair, '=')
+ if i < 0 {
+ // should never happen; see listEnvironWithUpper
+ panic("expand.listEnviron: did not expect malformed name-value pair: " + pair)
+ }
+ name, value := pair[:i], pair[i+1:]
+ if !fn(name, Variable{Exported: true, Kind: String, Str: value}) {
+ return
+ }
+ }
+}
diff --git a/vendor/mvdan.cc/sh/v3/expand/expand.go b/vendor/mvdan.cc/sh/v3/expand/expand.go
new file mode 100644
index 00000000..a3152dce
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/expand.go
@@ -0,0 +1,1038 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+package expand
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/fs"
+ "os"
+ "os/user"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "mvdan.cc/sh/v3/pattern"
+ "mvdan.cc/sh/v3/syntax"
+)
+
+// A Config specifies details about how shell expansion should be performed. The
+// zero value is a valid configuration.
+type Config struct {
+ // Env is used to get and set environment variables when performing
+ // shell expansions. Some special parameters are also expanded via this
+ // interface, such as:
+ //
+ // * "#", "@", "*", "0"-"9" for the shell's parameters
+ // * "?", "$", "PPID" for the shell's status and process
+ // * "HOME foo" to retrieve user foo's home directory (if unset,
+ // os/user.Lookup will be used)
+ //
+ // If nil, there are no environment variables set. Use
+ // ListEnviron(os.Environ()...) to use the system's environment
+ // variables.
+ Env Environ
+
+ // CmdSubst expands a command substitution node, writing its standard
+ // output to the provided io.Writer.
+ //
+ // If nil, encountering a command substitution will result in an
+ // UnexpectedCommandError.
+ CmdSubst func(io.Writer, *syntax.CmdSubst) error
+
+ // ProcSubst expands a process substitution node.
+ //
+ // Note that this feature is a work in progress, and the signature of
+ // this field might change until #451 is completely fixed.
+ ProcSubst func(*syntax.ProcSubst) (string, error)
+
+ // TODO(v4): update to os.Readdir with fs.DirEntry.
+ // We could possibly expose that as a preferred ReadDir2 before then,
+ // to allow users to opt into better performance in v3.
+
+ // ReadDir is used for file path globbing. If nil, globbing is disabled.
+ // Use ioutil.ReadDir to use the filesystem directly.
+ ReadDir func(string) ([]os.FileInfo, error)
+
+ // GlobStar corresponds to the shell option that allows globbing with
+ // "**".
+ GlobStar bool
+
+ // NullGlob corresponds to the shell option that allows globbing
+ // patterns which match nothing to result in zero fields.
+ NullGlob bool
+
+ // NoUnset corresponds to the shell option that treats unset variables
+ // as errors.
+ NoUnset bool
+
+ bufferAlloc bytes.Buffer // TODO: use strings.Builder
+ fieldAlloc [4]fieldPart
+ fieldsAlloc [4][]fieldPart
+
+ ifs string
+ // A pointer to a parameter expansion node, if we're inside one.
+ // Necessary for ${LINENO}.
+ curParam *syntax.ParamExp
+}
+
+// UnexpectedCommandError is returned if a command substitution is encountered
+// when Config.CmdSubst is nil.
+type UnexpectedCommandError struct {
+ Node *syntax.CmdSubst
+}
+
+func (u UnexpectedCommandError) Error() string {
+ return fmt.Sprintf("unexpected command substitution at %s", u.Node.Pos())
+}
+
+var zeroConfig = &Config{}
+
+func prepareConfig(cfg *Config) *Config {
+ if cfg == nil {
+ cfg = zeroConfig
+ }
+ if cfg.Env == nil {
+ cfg.Env = FuncEnviron(func(string) string { return "" })
+ }
+
+ cfg.ifs = " \t\n"
+ if vr := cfg.Env.Get("IFS"); vr.IsSet() {
+ cfg.ifs = vr.String()
+ }
+ return cfg
+}
+
+func (cfg *Config) ifsRune(r rune) bool {
+ for _, r2 := range cfg.ifs {
+ if r == r2 {
+ return true
+ }
+ }
+ return false
+}
+
+func (cfg *Config) ifsJoin(strs []string) string {
+ sep := ""
+ if cfg.ifs != "" {
+ sep = cfg.ifs[:1]
+ }
+ return strings.Join(strs, sep)
+}
+
+func (cfg *Config) strBuilder() *bytes.Buffer {
+ b := &cfg.bufferAlloc
+ b.Reset()
+ return b
+}
+
+func (cfg *Config) envGet(name string) string {
+ return cfg.Env.Get(name).String()
+}
+
+func (cfg *Config) envSet(name, value string) error {
+ wenv, ok := cfg.Env.(WriteEnviron)
+ if !ok {
+ return fmt.Errorf("environment is read-only")
+ }
+ return wenv.Set(name, Variable{Kind: String, Str: value})
+}
+
+// Literal expands a single shell word. It is similar to Fields, but the result
+// is a single string. This is the behavior when a word is used as the value in
+// a shell variable assignment, for example.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func Literal(cfg *Config, word *syntax.Word) (string, error) {
+ if word == nil {
+ return "", nil
+ }
+ cfg = prepareConfig(cfg)
+ field, err := cfg.wordField(word.Parts, quoteNone)
+ if err != nil {
+ return "", err
+ }
+ return cfg.fieldJoin(field), nil
+}
+
+// Document expands a single shell word as if it were within double quotes. It
+// is similar to Literal, but without brace expansion, tilde expansion, and
+// globbing.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func Document(cfg *Config, word *syntax.Word) (string, error) {
+ if word == nil {
+ return "", nil
+ }
+ cfg = prepareConfig(cfg)
+ field, err := cfg.wordField(word.Parts, quoteDouble)
+ if err != nil {
+ return "", err
+ }
+ return cfg.fieldJoin(field), nil
+}
+
+const patMode = pattern.Filenames | pattern.Braces
+
+// Pattern expands a single shell word as a pattern, using syntax.QuotePattern
+// on any non-quoted parts of the input word. The result can be used on
+// syntax.TranslatePattern directly.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func Pattern(cfg *Config, word *syntax.Word) (string, error) {
+ cfg = prepareConfig(cfg)
+ field, err := cfg.wordField(word.Parts, quoteNone)
+ if err != nil {
+ return "", err
+ }
+ buf := cfg.strBuilder()
+ for _, part := range field {
+ if part.quote > quoteNone {
+ buf.WriteString(pattern.QuoteMeta(part.val, patMode))
+ } else {
+ buf.WriteString(part.val)
+ }
+ }
+ return buf.String(), nil
+}
+
+// Format expands a format string with a number of arguments, following the
+// shell's format specifications. These include printf(1), among others.
+//
+// The resulting string is returned, along with the number of arguments used.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func Format(cfg *Config, format string, args []string) (string, int, error) {
+ cfg = prepareConfig(cfg)
+ buf := cfg.strBuilder()
+
+ consumed, err := formatIntoBuffer(buf, format, args)
+ if err != nil {
+ return "", 0, err
+ }
+
+ return buf.String(), consumed, err
+}
+
+// Format expands a format string with a number of arguments, following the
+// shell's format specifications. These include printf(1), among others.
+//
+// The resulting string is written to the provided buffer, and the number
+// of arguments used is returned.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func formatIntoBuffer(buf *bytes.Buffer, format string, args []string) (int, error) {
+ var fmts []byte
+ initialArgs := len(args)
+
+formatLoop:
+ for i := 0; i < len(format); i++ {
+ // readDigits reads from 0 to max digits, either octal or
+ // hexadecimal.
+ readDigits := func(max int, hex bool) string {
+ j := 0
+ for ; j < max; j++ {
+ c := format[i+j]
+ if (c >= '0' && c <= '9') ||
+ (hex && c >= 'a' && c <= 'f') ||
+ (hex && c >= 'A' && c <= 'F') {
+ // valid octal or hex char
+ } else {
+ break
+ }
+ }
+ digits := format[i : i+j]
+ i += j - 1 // -1 since the outer loop does i++
+ return digits
+ }
+ c := format[i]
+ switch {
+ case c == '\\': // escaped
+ i++
+ switch c = format[i]; c {
+ case 'a': // bell
+ buf.WriteByte('\a')
+ case 'b': // backspace
+ buf.WriteByte('\b')
+ case 'e', 'E': // escape
+ buf.WriteByte('\x1b')
+ case 'f': // form feed
+ buf.WriteByte('\f')
+ case 'n': // new line
+ buf.WriteByte('\n')
+ case 'r': // carriage return
+ buf.WriteByte('\r')
+ case 't': // horizontal tab
+ buf.WriteByte('\t')
+ case 'v': // vertical tab
+ buf.WriteByte('\v')
+ case '\\', '\'', '"', '?': // just the character
+ buf.WriteByte(c)
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ digits := readDigits(3, false)
+ // if digits don't fit in 8 bits, 0xff via strconv
+ n, _ := strconv.ParseUint(digits, 8, 8)
+ buf.WriteByte(byte(n))
+ case 'x', 'u', 'U':
+ i++
+ max := 2
+ if c == 'u' {
+ max = 4
+ } else if c == 'U' {
+ max = 8
+ }
+ digits := readDigits(max, true)
+ if len(digits) > 0 {
+ // can't error
+ n, _ := strconv.ParseUint(digits, 16, 32)
+ if n == 0 {
+ // If we're about to print \x00,
+ // stop the entire loop, like bash.
+ break formatLoop
+ }
+ if c == 'x' {
+ // always as a single byte
+ buf.WriteByte(byte(n))
+ } else {
+ buf.WriteRune(rune(n))
+ }
+ break
+ }
+ fallthrough
+ default: // no escape sequence
+ buf.WriteByte('\\')
+ buf.WriteByte(c)
+ }
+ case len(fmts) > 0:
+ switch c {
+ case '%':
+ buf.WriteByte('%')
+ fmts = nil
+ case 'c':
+ var b byte
+ if len(args) > 0 {
+ arg := ""
+ arg, args = args[0], args[1:]
+ if len(arg) > 0 {
+ b = arg[0]
+ }
+ }
+ buf.WriteByte(b)
+ fmts = nil
+ case '+', '-', ' ':
+ if len(fmts) > 1 {
+ return 0, fmt.Errorf("invalid format char: %c", c)
+ }
+ fmts = append(fmts, c)
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ fmts = append(fmts, c)
+ case 's', 'b', 'd', 'i', 'u', 'o', 'x':
+ arg := ""
+ if len(args) > 0 {
+ arg, args = args[0], args[1:]
+ }
+ var farg interface{}
+ if c == 'b' {
+ // Passing in nil for args ensures that % format
+ // strings aren't processed; only escape sequences
+ // will be handled.
+ _, err := formatIntoBuffer(buf, arg, nil)
+ if err != nil {
+ return 0, err
+ }
+ } else if c != 's' {
+ n, _ := strconv.ParseInt(arg, 0, 0)
+ if c == 'i' || c == 'd' {
+ farg = int(n)
+ } else {
+ farg = uint(n)
+ }
+ if c == 'i' || c == 'u' {
+ c = 'd'
+ }
+ } else {
+ farg = arg
+ }
+ if farg != nil {
+ fmts = append(fmts, c)
+ fmt.Fprintf(buf, string(fmts), farg)
+ }
+ fmts = nil
+ default:
+ return 0, fmt.Errorf("invalid format char: %c", c)
+ }
+ case args != nil && c == '%':
+ // if args == nil, we are not doing format
+ // arguments
+ fmts = []byte{c}
+ default:
+ buf.WriteByte(c)
+ }
+ }
+ if len(fmts) > 0 {
+ return 0, fmt.Errorf("missing format char")
+ }
+ return initialArgs - len(args), nil
+}
+
+func (cfg *Config) fieldJoin(parts []fieldPart) string {
+ switch len(parts) {
+ case 0:
+ return ""
+ case 1: // short-cut without a string copy
+ return parts[0].val
+ }
+ buf := cfg.strBuilder()
+ for _, part := range parts {
+ buf.WriteString(part.val)
+ }
+ return buf.String()
+}
+
+func (cfg *Config) escapedGlobField(parts []fieldPart) (escaped string, glob bool) {
+ buf := cfg.strBuilder()
+ for _, part := range parts {
+ if part.quote > quoteNone {
+ buf.WriteString(pattern.QuoteMeta(part.val, patMode))
+ continue
+ }
+ buf.WriteString(part.val)
+ if pattern.HasMeta(part.val, patMode) {
+ glob = true
+ }
+ }
+ if glob { // only copy the string if it will be used
+ escaped = buf.String()
+ }
+ return escaped, glob
+}
+
+// Fields expands a number of words as if they were arguments in a shell
+// command. This includes brace expansion, tilde expansion, parameter expansion,
+// command substitution, arithmetic expansion, and quote removal.
+func Fields(cfg *Config, words ...*syntax.Word) ([]string, error) {
+ cfg = prepareConfig(cfg)
+ fields := make([]string, 0, len(words))
+ dir := cfg.envGet("PWD")
+ for _, word := range words {
+ word := *word // make a copy, since SplitBraces replaces the Parts slice
+ afterBraces := []*syntax.Word{&word}
+ if syntax.SplitBraces(&word) {
+ afterBraces = Braces(&word)
+ }
+ for _, word2 := range afterBraces {
+ wfields, err := cfg.wordFields(word2.Parts)
+ if err != nil {
+ return nil, err
+ }
+ for _, field := range wfields {
+ path, doGlob := cfg.escapedGlobField(field)
+ var matches []string
+ var syntaxError *pattern.SyntaxError
+ if doGlob && cfg.ReadDir != nil {
+ matches, err = cfg.glob(dir, path)
+ if !errors.As(err, &syntaxError) {
+ if err != nil {
+ return nil, err
+ }
+ if len(matches) > 0 || cfg.NullGlob {
+ fields = append(fields, matches...)
+ continue
+ }
+ }
+ }
+ fields = append(fields, cfg.fieldJoin(field))
+ }
+ }
+ }
+ return fields, nil
+}
+
+type fieldPart struct {
+ val string
+ quote quoteLevel
+}
+
+type quoteLevel uint
+
+const (
+ quoteNone quoteLevel = iota
+ quoteDouble
+ quoteSingle
+)
+
+func (cfg *Config) wordField(wps []syntax.WordPart, ql quoteLevel) ([]fieldPart, error) {
+ var field []fieldPart
+ for i, wp := range wps {
+ switch x := wp.(type) {
+ case *syntax.Lit:
+ s := x.Value
+ if i == 0 && ql == quoteNone {
+ if prefix, rest := cfg.expandUser(s); prefix != "" {
+ // TODO: return two separate fieldParts,
+ // like in wordFields?
+ s = prefix + rest
+ }
+ }
+ if ql == quoteDouble && strings.Contains(s, "\\") {
+ buf := cfg.strBuilder()
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if b == '\\' && i+1 < len(s) {
+ switch s[i+1] {
+ case '"', '\\', '$', '`': // special chars
+ continue
+ }
+ }
+ buf.WriteByte(b)
+ }
+ s = buf.String()
+ }
+ if i := strings.IndexByte(s, '\x00'); i >= 0 {
+ s = s[:i]
+ }
+ field = append(field, fieldPart{val: s})
+ case *syntax.SglQuoted:
+ fp := fieldPart{quote: quoteSingle, val: x.Value}
+ if x.Dollar {
+ fp.val, _, _ = Format(cfg, fp.val, nil)
+ }
+ field = append(field, fp)
+ case *syntax.DblQuoted:
+ wfield, err := cfg.wordField(x.Parts, quoteDouble)
+ if err != nil {
+ return nil, err
+ }
+ for _, part := range wfield {
+ part.quote = quoteDouble
+ field = append(field, part)
+ }
+ case *syntax.ParamExp:
+ val, err := cfg.paramExp(x)
+ if err != nil {
+ return nil, err
+ }
+ field = append(field, fieldPart{val: val})
+ case *syntax.CmdSubst:
+ val, err := cfg.cmdSubst(x)
+ if err != nil {
+ return nil, err
+ }
+ field = append(field, fieldPart{val: val})
+ case *syntax.ArithmExp:
+ n, err := Arithm(cfg, x.X)
+ if err != nil {
+ return nil, err
+ }
+ field = append(field, fieldPart{val: strconv.Itoa(n)})
+ case *syntax.ProcSubst:
+ path, err := cfg.ProcSubst(x)
+ if err != nil {
+ return nil, err
+ }
+ field = append(field, fieldPart{val: path})
+ default:
+ panic(fmt.Sprintf("unhandled word part: %T", x))
+ }
+ }
+ return field, nil
+}
+
+func (cfg *Config) cmdSubst(cs *syntax.CmdSubst) (string, error) {
+ if cfg.CmdSubst == nil {
+ return "", UnexpectedCommandError{Node: cs}
+ }
+ buf := cfg.strBuilder()
+ if err := cfg.CmdSubst(buf, cs); err != nil {
+ return "", err
+ }
+ out := buf.String()
+ if strings.IndexByte(out, '\x00') >= 0 {
+ out = strings.ReplaceAll(out, "\x00", "")
+ }
+ return strings.TrimRight(out, "\n"), nil
+}
+
+func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) {
+ fields := cfg.fieldsAlloc[:0]
+ curField := cfg.fieldAlloc[:0]
+ allowEmpty := false
+ flush := func() {
+ if len(curField) == 0 {
+ return
+ }
+ fields = append(fields, curField)
+ curField = nil
+ }
+ splitAdd := func(val string) {
+ fieldStart := -1
+ for i, r := range val {
+ if cfg.ifsRune(r) {
+ if fieldStart >= 0 { // ending a field
+ curField = append(curField, fieldPart{val: val[fieldStart:i]})
+ fieldStart = -1
+ }
+ flush()
+ } else {
+ if fieldStart < 0 { // starting a new field
+ fieldStart = i
+ }
+ }
+ }
+ if fieldStart >= 0 { // ending a field without IFS
+ curField = append(curField, fieldPart{val: val[fieldStart:]})
+ }
+ }
+ for i, wp := range wps {
+ switch x := wp.(type) {
+ case *syntax.Lit:
+ s := x.Value
+ if i == 0 {
+ prefix, rest := cfg.expandUser(s)
+ curField = append(curField, fieldPart{
+ quote: quoteSingle,
+ val: prefix,
+ })
+ s = rest
+ }
+ if strings.Contains(s, "\\") {
+ buf := cfg.strBuilder()
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if b == '\\' {
+ if i++; i >= len(s) {
+ break
+ }
+ b = s[i]
+ }
+ buf.WriteByte(b)
+ }
+ s = buf.String()
+ }
+ curField = append(curField, fieldPart{val: s})
+ case *syntax.SglQuoted:
+ allowEmpty = true
+ fp := fieldPart{quote: quoteSingle, val: x.Value}
+ if x.Dollar {
+ fp.val, _, _ = Format(cfg, fp.val, nil)
+ }
+ curField = append(curField, fp)
+ case *syntax.DblQuoted:
+ if len(x.Parts) == 1 {
+ pe, _ := x.Parts[0].(*syntax.ParamExp)
+ if elems := cfg.quotedElemFields(pe); elems != nil {
+ for i, elem := range elems {
+ if i > 0 {
+ flush()
+ }
+ curField = append(curField, fieldPart{
+ quote: quoteDouble,
+ val: elem,
+ })
+ }
+ continue
+ }
+ }
+ allowEmpty = true
+ wfield, err := cfg.wordField(x.Parts, quoteDouble)
+ if err != nil {
+ return nil, err
+ }
+ for _, part := range wfield {
+ part.quote = quoteDouble
+ curField = append(curField, part)
+ }
+ case *syntax.ParamExp:
+ val, err := cfg.paramExp(x)
+ if err != nil {
+ return nil, err
+ }
+ splitAdd(val)
+ case *syntax.CmdSubst:
+ val, err := cfg.cmdSubst(x)
+ if err != nil {
+ return nil, err
+ }
+ splitAdd(val)
+ case *syntax.ArithmExp:
+ n, err := Arithm(cfg, x.X)
+ if err != nil {
+ return nil, err
+ }
+ curField = append(curField, fieldPart{val: strconv.Itoa(n)})
+ case *syntax.ProcSubst:
+ path, err := cfg.ProcSubst(x)
+ if err != nil {
+ return nil, err
+ }
+ splitAdd(path)
+ case *syntax.ExtGlob:
+ return nil, fmt.Errorf("extended globbing is not supported")
+ default:
+ panic(fmt.Sprintf("unhandled word part: %T", x))
+ }
+ }
+ flush()
+ if allowEmpty && len(fields) == 0 {
+ fields = append(fields, curField)
+ }
+ return fields, nil
+}
+
+// quotedElemFields returns the list of elements resulting from a quoted
+// parameter expansion that should be treated especially, like "${foo[@]}".
+func (cfg *Config) quotedElemFields(pe *syntax.ParamExp) []string {
+ if pe == nil || pe.Length || pe.Width {
+ return nil
+ }
+ name := pe.Param.Value
+ if pe.Excl {
+ switch pe.Names {
+ case syntax.NamesPrefixWords: // "${!prefix@}"
+ return cfg.namesByPrefix(pe.Param.Value)
+ case syntax.NamesPrefix: // "${!prefix*}"
+ return nil
+ }
+ switch nodeLit(pe.Index) {
+ case "@": // "${!name[@]}"
+ switch vr := cfg.Env.Get(name); vr.Kind {
+ case Indexed:
+ keys := make([]string, 0, len(vr.Map))
+ for key := range vr.List {
+ keys = append(keys, strconv.Itoa(key))
+ }
+ return keys
+ case Associative:
+ keys := make([]string, 0, len(vr.Map))
+ for key := range vr.Map {
+ keys = append(keys, key)
+ }
+ return keys
+ }
+ }
+ return nil
+ }
+ switch name {
+ case "*": // "${*}"
+ return []string{cfg.ifsJoin(cfg.Env.Get(name).List)}
+ case "@": // "${@}"
+ return cfg.Env.Get(name).List
+ }
+ switch nodeLit(pe.Index) {
+ case "@": // "${name[@]}"
+ switch vr := cfg.Env.Get(name); vr.Kind {
+ case Indexed:
+ return vr.List
+ case Associative:
+ elems := make([]string, 0, len(vr.Map))
+ for _, elem := range vr.Map {
+ elems = append(elems, elem)
+ }
+ return elems
+ }
+ case "*": // "${name[*]}"
+ if vr := cfg.Env.Get(name); vr.Kind == Indexed {
+ return []string{cfg.ifsJoin(vr.List)}
+ }
+ }
+ return nil
+}
+
+func (cfg *Config) expandUser(field string) (prefix, rest string) {
+ if len(field) == 0 || field[0] != '~' {
+ return "", field
+ }
+ name := field[1:]
+ if i := strings.Index(name, "/"); i >= 0 {
+ rest = name[i:]
+ name = name[:i]
+ }
+ if name == "" {
+ // Current user; try via "HOME", otherwise fall back to the
+ // system's appropriate home dir env var. Don't use os/user, as
+ // that's overkill. We can't use os.UserHomeDir, because we want
+ // to use cfg.Env, and we always want to check "HOME" first.
+
+ if vr := cfg.Env.Get("HOME"); vr.IsSet() {
+ return vr.String(), rest
+ }
+
+ if runtime.GOOS == "windows" {
+ if vr := cfg.Env.Get("USERPROFILE"); vr.IsSet() {
+ return vr.String(), rest
+ }
+ }
+ return "", field
+ }
+
+ // Not the current user; try via "HOME ", otherwise fall back to
+ // os/user. There isn't a way to lookup user home dirs without cgo.
+
+ if vr := cfg.Env.Get("HOME " + name); vr.IsSet() {
+ return vr.String(), rest
+ }
+
+ u, err := user.Lookup(name)
+ if err != nil {
+ return "", field
+ }
+ return u.HomeDir, rest
+}
+
+func findAllIndex(pat, name string, n int) [][]int {
+ expr, err := pattern.Regexp(pat, 0)
+ if err != nil {
+ return nil
+ }
+ rx := regexp.MustCompile(expr)
+ return rx.FindAllStringIndex(name, n)
+}
+
+var rxGlobStar = regexp.MustCompile(".*")
+
+// pathJoin2 is a simpler version of filepath.Join without cleaning the result,
+// since that's needed for globbing.
+func pathJoin2(elem1, elem2 string) string {
+ if elem1 == "" {
+ return elem2
+ }
+ if strings.HasSuffix(elem1, string(filepath.Separator)) {
+ return elem1 + elem2
+ }
+ return elem1 + string(filepath.Separator) + elem2
+}
+
+// pathSplit splits a file path into its elements, retaining empty ones. Before
+// splitting, slashes are replaced with filepath.Separator, so that splitting
+// Unix paths on Windows works as well.
+func pathSplit(path string) []string {
+ path = filepath.FromSlash(path)
+ return strings.Split(path, string(filepath.Separator))
+}
+
+func (cfg *Config) glob(base, pat string) ([]string, error) {
+ parts := pathSplit(pat)
+ matches := []string{""}
+ if filepath.IsAbs(pat) {
+ if parts[0] == "" {
+ // unix-like
+ matches[0] = string(filepath.Separator)
+ } else {
+ // windows (for some reason it won't work without the
+ // trailing separator)
+ matches[0] = parts[0] + string(filepath.Separator)
+ }
+ parts = parts[1:]
+ }
+ // TODO: as an optimization, we could do chunks of the path all at once,
+ // like doing a single stat for "/foo/bar" in "/foo/bar/*".
+
+ // TODO: Another optimization would be to reduce the number of ReadDir calls.
+ // For example, /foo/* can end up doing one duplicate call:
+ //
+ // ReadDir("/foo") to ensure that "/foo/" exists and only matches a directory
+ // ReadDir("/foo") glob "*"
+
+ for i, part := range parts {
+ // Keep around for debugging.
+ // log.Printf("matches %q part %d %q", matches, i, part)
+
+ wantDir := i < len(parts)-1
+ switch {
+ case part == "", part == ".", part == "..":
+ for i, dir := range matches {
+ matches[i] = pathJoin2(dir, part)
+ }
+ continue
+ case !pattern.HasMeta(part, patMode):
+ var newMatches []string
+ for _, dir := range matches {
+ match := dir
+ if !filepath.IsAbs(match) {
+ match = filepath.Join(base, match)
+ }
+ match = pathJoin2(match, part)
+ // We can't use ReadDir on the parent and match the directory
+ // entry by name, because short paths on Windows break that.
+ // Our only option is to ReadDir on the directory entry itself,
+ // which can be wasteful if we only want to see if it exists,
+ // but at least it's correct in all scenarios.
+ if _, err := cfg.ReadDir(match); err != nil {
+ const errPathNotFound = syscall.Errno(3) // from syscall/types_windows.go, to avoid a build tag
+ var pathErr *os.PathError
+ if runtime.GOOS == "windows" && errors.As(err, &pathErr) && pathErr.Err == errPathNotFound {
+ // Unfortunately, os.File.Readdir on a regular file on
+ // Windows returns an error that satisfies ErrNotExist.
+ // Luckily, it returns a special "path not found" rather
+ // than the normal "file not found" for missing files,
+ // so we can use that knowledge to work around the bug.
+ // See https://github.com/golang/go/issues/46734.
+ // TODO: remove when the Go issue above is resolved.
+ } else if errors.Is(err, fs.ErrNotExist) {
+ continue // simply doesn't exist
+ }
+ if wantDir {
+ continue // exists but not a directory
+ }
+ }
+ newMatches = append(newMatches, pathJoin2(dir, part))
+ }
+ matches = newMatches
+ continue
+ case part == "**" && cfg.GlobStar:
+ // Find all recursive matches for "**".
+ // Note that we need the results to be in depth-first order,
+ // and to avoid recursion, we use a slice as a stack.
+ // Since we pop from the back, we populate the stack backwards.
+ stack := make([]string, 0, len(matches))
+ for i := len(matches) - 1; i >= 0; i-- {
+ // "a/**" should match "a/ a/b a/b/cfg ...";
+ // note how the zero-match case has a trailing separator.
+ stack = append(stack, pathJoin2(matches[i], ""))
+ }
+ matches = matches[:0]
+ var newMatches []string // to reuse its capacity
+ for len(stack) > 0 {
+ dir := stack[len(stack)-1]
+ stack = stack[:len(stack)-1]
+
+ // Don't include the original "" match as it's not a valid path.
+ if dir != "" {
+ matches = append(matches, dir)
+ }
+
+ // If dir is not a directory, we keep the stack as-is and continue.
+ newMatches = newMatches[:0]
+ newMatches, _ = cfg.globDir(base, dir, rxGlobStar, false, wantDir, newMatches)
+ for i := len(newMatches) - 1; i >= 0; i-- {
+ stack = append(stack, newMatches[i])
+ }
+ }
+ continue
+ }
+ expr, err := pattern.Regexp(part, pattern.Filenames|pattern.EntireString)
+ if err != nil {
+ return nil, err
+ }
+ rx := regexp.MustCompile(expr)
+ matchHidden := part[0] == byte('.')
+ var newMatches []string
+ for _, dir := range matches {
+ newMatches, err = cfg.globDir(base, dir, rx, matchHidden, wantDir, newMatches)
+ if err != nil {
+ return nil, err
+ }
+ }
+ matches = newMatches
+ }
+ return matches, nil
+}
+
+func (cfg *Config) globDir(base, dir string, rx *regexp.Regexp, matchHidden bool, wantDir bool, matches []string) ([]string, error) {
+ fullDir := dir
+ if !filepath.IsAbs(dir) {
+ fullDir = filepath.Join(base, dir)
+ }
+ infos, err := cfg.ReadDir(fullDir)
+ if err != nil {
+ // We still want to return matches, for the sake of reusing slices.
+ return matches, err
+ }
+ for _, info := range infos {
+ name := info.Name()
+ if !wantDir {
+ // No filtering.
+ } else if mode := info.Mode(); mode&os.ModeSymlink != 0 {
+ // We need to know if the symlink points to a directory.
+ // This requires an extra syscall, as ReadDir on the parent directory
+ // does not follow symlinks for each of the directory entries.
+ // ReadDir is somewhat wasteful here, as we only want its error result,
+ // but we could try to reuse its result as per the TODO in Config.glob.
+ if _, err := cfg.ReadDir(filepath.Join(fullDir, info.Name())); err != nil {
+ continue
+ }
+ } else if !mode.IsDir() {
+ // Not a symlink nor a directory.
+ continue
+ }
+ if !matchHidden && name[0] == '.' {
+ continue
+ }
+ if rx.MatchString(name) {
+ matches = append(matches, pathJoin2(dir, name))
+ }
+ }
+ return matches, nil
+}
+
+// ReadFields TODO write doc.
+//
+// The config specifies shell expansion options; nil behaves the same as an
+// empty config.
+func ReadFields(cfg *Config, s string, n int, raw bool) []string {
+ cfg = prepareConfig(cfg)
+ type pos struct {
+ start, end int
+ }
+ var fpos []pos
+
+ runes := make([]rune, 0, len(s))
+ infield := false
+ esc := false
+ for _, r := range s {
+ if infield {
+ if cfg.ifsRune(r) && (raw || !esc) {
+ fpos[len(fpos)-1].end = len(runes)
+ infield = false
+ }
+ } else {
+ if !cfg.ifsRune(r) && (raw || !esc) {
+ fpos = append(fpos, pos{start: len(runes), end: -1})
+ infield = true
+ }
+ }
+ if r == '\\' {
+ if raw || esc {
+ runes = append(runes, r)
+ }
+ esc = !esc
+ continue
+ }
+ runes = append(runes, r)
+ esc = false
+ }
+ if len(fpos) == 0 {
+ return nil
+ }
+ if infield {
+ fpos[len(fpos)-1].end = len(runes)
+ }
+
+ switch {
+ case n == 1:
+ // include heading/trailing IFSs
+ fpos[0].start, fpos[0].end = 0, len(runes)
+ fpos = fpos[:1]
+ case n != -1 && n < len(fpos):
+ // combine to max n fields
+ fpos[n-1].end = fpos[len(fpos)-1].end
+ fpos = fpos[:n]
+ }
+
+ fields := make([]string, len(fpos))
+ for i, p := range fpos {
+ fields[i] = string(runes[p.start:p.end])
+ }
+ return fields
+}
diff --git a/vendor/mvdan.cc/sh/v3/expand/param.go b/vendor/mvdan.cc/sh/v3/expand/param.go
new file mode 100644
index 00000000..bf0d2382
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/expand/param.go
@@ -0,0 +1,428 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+package expand
+
+import (
+ "fmt"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "mvdan.cc/sh/v3/pattern"
+ "mvdan.cc/sh/v3/syntax"
+)
+
+func nodeLit(node syntax.Node) string {
+ if word, ok := node.(*syntax.Word); ok {
+ return word.Lit()
+ }
+ return ""
+}
+
+type UnsetParameterError struct {
+ Node *syntax.ParamExp
+ Message string
+}
+
+func (u UnsetParameterError) Error() string {
+ return fmt.Sprintf("%s: %s", u.Node.Param.Value, u.Message)
+}
+
+func overridingUnset(pe *syntax.ParamExp) bool {
+ if pe.Exp == nil {
+ return false
+ }
+ switch pe.Exp.Op {
+ case syntax.AlternateUnset, syntax.AlternateUnsetOrNull,
+ syntax.DefaultUnset, syntax.DefaultUnsetOrNull,
+ syntax.ErrorUnset, syntax.ErrorUnsetOrNull,
+ syntax.AssignUnset, syntax.AssignUnsetOrNull:
+ return true
+ }
+ return false
+}
+
+func (cfg *Config) paramExp(pe *syntax.ParamExp) (string, error) {
+ oldParam := cfg.curParam
+ cfg.curParam = pe
+ defer func() { cfg.curParam = oldParam }()
+
+ name := pe.Param.Value
+ index := pe.Index
+ switch name {
+ case "@", "*":
+ index = &syntax.Word{Parts: []syntax.WordPart{
+ &syntax.Lit{Value: name},
+ }}
+ }
+ var vr Variable
+ switch name {
+ case "LINENO":
+ // This is the only parameter expansion that the environment
+ // interface cannot satisfy.
+ line := uint64(cfg.curParam.Pos().Line())
+ vr = Variable{Kind: String, Str: strconv.FormatUint(line, 10)}
+ default:
+ vr = cfg.Env.Get(name)
+ }
+ orig := vr
+ _, vr = vr.Resolve(cfg.Env)
+ if cfg.NoUnset && vr.Kind == Unset && !overridingUnset(pe) {
+ return "", UnsetParameterError{
+ Node: pe,
+ Message: "unbound variable",
+ }
+ }
+
+ var sliceOffset, sliceLen int
+ if pe.Slice != nil {
+ var err error
+ if pe.Slice.Offset != nil {
+ sliceOffset, err = Arithm(cfg, pe.Slice.Offset)
+ if err != nil {
+ return "", err
+ }
+ }
+ if pe.Slice.Length != nil {
+ sliceLen, err = Arithm(cfg, pe.Slice.Length)
+ if err != nil {
+ return "", err
+ }
+ }
+ }
+
+ var (
+ str string
+ elems []string
+
+ indexAllElements bool // true if var has been accessed with * or @ index
+ callVarInd = true
+ )
+
+ switch nodeLit(index) {
+ case "@", "*":
+ switch vr.Kind {
+ case Unset:
+ elems = nil
+ indexAllElements = true
+ case Indexed:
+ indexAllElements = true
+ callVarInd = false
+ elems = vr.List
+ slicePos := func(n int) int {
+ if n < 0 {
+ n = len(elems) + n
+ if n < 0 {
+ n = len(elems)
+ }
+ } else if n > len(elems) {
+ n = len(elems)
+ }
+ return n
+ }
+ if pe.Slice != nil && pe.Slice.Offset != nil {
+ elems = elems[slicePos(sliceOffset):]
+ }
+ if pe.Slice != nil && pe.Slice.Length != nil {
+ elems = elems[:slicePos(sliceLen)]
+ }
+ str = strings.Join(elems, " ")
+ }
+ }
+ if callVarInd {
+ var err error
+ str, err = cfg.varInd(vr, index)
+ if err != nil {
+ return "", err
+ }
+ }
+ if !indexAllElements {
+ elems = []string{str}
+ }
+
+ switch {
+ case pe.Length:
+ n := len(elems)
+ switch nodeLit(index) {
+ case "@", "*":
+ default:
+ n = utf8.RuneCountInString(str)
+ }
+ str = strconv.Itoa(n)
+ case pe.Excl:
+ var strs []string
+ switch {
+ case pe.Names != 0:
+ strs = cfg.namesByPrefix(pe.Param.Value)
+ case orig.Kind == NameRef:
+ strs = append(strs, orig.Str)
+ case pe.Index != nil && vr.Kind == Indexed:
+ for i, e := range vr.List {
+ if e != "" {
+ strs = append(strs, strconv.Itoa(i))
+ }
+ }
+ case pe.Index != nil && vr.Kind == Associative:
+ for k := range vr.Map {
+ strs = append(strs, k)
+ }
+ case vr.Kind == Unset:
+ return "", fmt.Errorf("invalid indirect expansion")
+ case str == "":
+ return "", nil
+ default:
+ vr = cfg.Env.Get(str)
+ strs = append(strs, vr.String())
+ }
+ sort.Strings(strs)
+ str = strings.Join(strs, " ")
+ case pe.Slice != nil:
+ if callVarInd {
+ slicePos := func(n int) int {
+ if n < 0 {
+ n = len(str) + n
+ if n < 0 {
+ n = len(str)
+ }
+ } else if n > len(str) {
+ n = len(str)
+ }
+ return n
+ }
+ if pe.Slice.Offset != nil {
+ str = str[slicePos(sliceOffset):]
+ }
+ if pe.Slice.Length != nil {
+ str = str[:slicePos(sliceLen)]
+ }
+ } else { // elems are already sliced
+ }
+ case pe.Repl != nil:
+ orig, err := Pattern(cfg, pe.Repl.Orig)
+ if err != nil {
+ return "", err
+ }
+ with, err := Literal(cfg, pe.Repl.With)
+ if err != nil {
+ return "", err
+ }
+ n := 1
+ if pe.Repl.All {
+ n = -1
+ }
+ locs := findAllIndex(orig, str, n)
+ buf := cfg.strBuilder()
+ last := 0
+ for _, loc := range locs {
+ buf.WriteString(str[last:loc[0]])
+ buf.WriteString(with)
+ last = loc[1]
+ }
+ buf.WriteString(str[last:])
+ str = buf.String()
+ case pe.Exp != nil:
+ arg, err := Literal(cfg, pe.Exp.Word)
+ if err != nil {
+ return "", err
+ }
+ switch op := pe.Exp.Op; op {
+ case syntax.AlternateUnsetOrNull:
+ if str == "" {
+ break
+ }
+ fallthrough
+ case syntax.AlternateUnset:
+ if vr.IsSet() {
+ str = arg
+ }
+ case syntax.DefaultUnset:
+ if vr.IsSet() {
+ break
+ }
+ fallthrough
+ case syntax.DefaultUnsetOrNull:
+ if str == "" {
+ str = arg
+ }
+ case syntax.ErrorUnset:
+ if vr.IsSet() {
+ break
+ }
+ fallthrough
+ case syntax.ErrorUnsetOrNull:
+ if str == "" {
+ return "", UnsetParameterError{
+ Node: pe,
+ Message: arg,
+ }
+ }
+ case syntax.AssignUnset:
+ if vr.IsSet() {
+ break
+ }
+ fallthrough
+ case syntax.AssignUnsetOrNull:
+ if str == "" {
+ if err := cfg.envSet(name, arg); err != nil {
+ return "", err
+ }
+ str = arg
+ }
+ case syntax.RemSmallPrefix, syntax.RemLargePrefix,
+ syntax.RemSmallSuffix, syntax.RemLargeSuffix:
+ suffix := op == syntax.RemSmallSuffix || op == syntax.RemLargeSuffix
+ small := op == syntax.RemSmallPrefix || op == syntax.RemSmallSuffix
+ for i, elem := range elems {
+ elems[i] = removePattern(elem, arg, suffix, small)
+ }
+ str = strings.Join(elems, " ")
+ case syntax.UpperFirst, syntax.UpperAll,
+ syntax.LowerFirst, syntax.LowerAll:
+
+ caseFunc := unicode.ToLower
+ if op == syntax.UpperFirst || op == syntax.UpperAll {
+ caseFunc = unicode.ToUpper
+ }
+ all := op == syntax.UpperAll || op == syntax.LowerAll
+
+ // empty string means '?'; nothing to do there
+ expr, err := pattern.Regexp(arg, 0)
+ if err != nil {
+ return str, nil
+ }
+ rx := regexp.MustCompile(expr)
+
+ for i, elem := range elems {
+ rs := []rune(elem)
+ for ri, r := range rs {
+ if rx.MatchString(string(r)) {
+ rs[ri] = caseFunc(r)
+ if !all {
+ break
+ }
+ }
+ }
+ elems[i] = string(rs)
+ }
+ str = strings.Join(elems, " ")
+ case syntax.OtherParamOps:
+ switch arg {
+ case "Q":
+ str, err = syntax.Quote(str, syntax.LangBash)
+ if err != nil {
+ // Is this even possible? If a user runs into this panic,
+ // it's most likely a bug we need to fix.
+ panic(err)
+ }
+ case "E":
+ tail := str
+ var rns []rune
+ for tail != "" {
+ var rn rune
+ rn, _, tail, _ = strconv.UnquoteChar(tail, 0)
+ rns = append(rns, rn)
+ }
+ str = string(rns)
+ case "P", "A", "a":
+ panic(fmt.Sprintf("unhandled @%s param expansion", arg))
+ default:
+ panic(fmt.Sprintf("unexpected @%s param expansion", arg))
+ }
+ }
+ }
+ return str, nil
+}
+
+func removePattern(str, pat string, fromEnd, shortest bool) string {
+ var mode pattern.Mode
+ if shortest {
+ mode |= pattern.Shortest
+ }
+ expr, err := pattern.Regexp(pat, mode)
+ if err != nil {
+ return str
+ }
+ switch {
+ case fromEnd && shortest:
+ // use .* to get the right-most shortest match
+ expr = ".*(" + expr + ")$"
+ case fromEnd:
+ // simple suffix
+ expr = "(" + expr + ")$"
+ default:
+ // simple prefix
+ expr = "^(" + expr + ")"
+ }
+ // no need to check error as Translate returns one
+ rx := regexp.MustCompile(expr)
+ if loc := rx.FindStringSubmatchIndex(str); loc != nil {
+ // remove the original pattern (the submatch)
+ str = str[:loc[2]] + str[loc[3]:]
+ }
+ return str
+}
+
+func (cfg *Config) varInd(vr Variable, idx syntax.ArithmExpr) (string, error) {
+ if idx == nil {
+ return vr.String(), nil
+ }
+ switch vr.Kind {
+ case String:
+ n, err := Arithm(cfg, idx)
+ if err != nil {
+ return "", err
+ }
+ if n == 0 {
+ return vr.Str, nil
+ }
+ case Indexed:
+ switch nodeLit(idx) {
+ case "*", "@":
+ return strings.Join(vr.List, " "), nil
+ }
+ i, err := Arithm(cfg, idx)
+ if err != nil {
+ return "", err
+ }
+ if i < 0 {
+ return "", fmt.Errorf("negative array index")
+ }
+ if i < len(vr.List) {
+ return vr.List[i], nil
+ }
+ case Associative:
+ switch lit := nodeLit(idx); lit {
+ case "@", "*":
+ strs := make([]string, 0, len(vr.Map))
+ for _, val := range vr.Map {
+ strs = append(strs, val)
+ }
+ sort.Strings(strs)
+ if lit == "*" {
+ return cfg.ifsJoin(strs), nil
+ }
+ return strings.Join(strs, " "), nil
+ }
+ val, err := Literal(cfg, idx.(*syntax.Word))
+ if err != nil {
+ return "", err
+ }
+ return vr.Map[val], nil
+ }
+ return "", nil
+}
+
+func (cfg *Config) namesByPrefix(prefix string) []string {
+ var names []string
+ cfg.Env.Each(func(name string, vr Variable) bool {
+ if strings.HasPrefix(name, prefix) {
+ names = append(names, name)
+ }
+ return true
+ })
+ return names
+}
diff --git a/vendor/mvdan.cc/sh/v3/fileutil/file.go b/vendor/mvdan.cc/sh/v3/fileutil/file.go
new file mode 100644
index 00000000..1ccf6fef
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/fileutil/file.go
@@ -0,0 +1,85 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+// Package fileutil contains code to work with shell files, also known
+// as shell scripts.
+package fileutil
+
+import (
+ "io/fs"
+ "os"
+ "regexp"
+ "strings"
+)
+
+var (
+ shebangRe = regexp.MustCompile(`^#!\s?/(usr/)?bin/(env\s+)?(sh|bash|mksh|bats|zsh)(\s|$)`)
+ extRe = regexp.MustCompile(`\.(sh|bash|mksh|bats|zsh)$`)
+)
+
+// TODO: consider removing HasShebang in favor of Shebang in v4
+
+// HasShebang reports whether bs begins with a valid shell shebang.
+// It supports variations with /usr and env.
+func HasShebang(bs []byte) bool {
+ return Shebang(bs) != ""
+}
+
+// Shebang parses a "#!" sequence from the beginning of the input bytes,
+// and returns the shell that it points to.
+//
+// For instance, it returns "sh" for "#!/bin/sh",
+// and "bash" for "#!/usr/bin/env bash".
+func Shebang(bs []byte) string {
+ m := shebangRe.FindSubmatch(bs)
+ if m == nil {
+ return ""
+ }
+ return string(m[3])
+}
+
+// ScriptConfidence defines how likely a file is to be a shell script,
+// from complete certainty that it is not one to complete certainty that
+// it is one.
+type ScriptConfidence int
+
+const (
+ // ConfNotScript describes files which are definitely not shell scripts,
+ // such as non-regular files or files with a non-shell extension.
+ ConfNotScript ScriptConfidence = iota
+
+ // ConfIfShebang describes files which might be shell scripts, depending
+ // on the shebang line in the file's contents. Since CouldBeScript only
+ // works on os.FileInfo, the answer in this case can't be final.
+ ConfIfShebang
+
+ // ConfIsScript describes files which are definitely shell scripts,
+ // which are regular files with a valid shell extension.
+ ConfIsScript
+)
+
+// CouldBeScript is a shortcut for CouldBeScript2(fs.FileInfoToDirEntry(info)).
+//
+// Deprecated: prefer CouldBeScript2, which usually requires fewer syscalls.
+func CouldBeScript(info os.FileInfo) ScriptConfidence {
+ return CouldBeScript2(fs.FileInfoToDirEntry(info))
+}
+
+// CouldBeScript2 reports how likely a directory entry is to be a shell script.
+// It discards directories, symlinks, hidden files and files with non-shell
+// extensions.
+func CouldBeScript2(entry fs.DirEntry) ScriptConfidence {
+ name := entry.Name()
+ switch {
+ case entry.IsDir(), name[0] == '.':
+ return ConfNotScript
+ case entry.Type()&os.ModeSymlink != 0:
+ return ConfNotScript
+ case extRe.MatchString(name):
+ return ConfIsScript
+ case strings.IndexByte(name, '.') > 0:
+ return ConfNotScript // different extension
+ default:
+ return ConfIfShebang
+ }
+}
diff --git a/vendor/mvdan.cc/sh/v3/pattern/pattern.go b/vendor/mvdan.cc/sh/v3/pattern/pattern.go
new file mode 100644
index 00000000..bde1ca71
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/pattern/pattern.go
@@ -0,0 +1,335 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+// Package pattern allows working with shell pattern matching notation, also
+// known as wildcards or globbing.
+//
+// For reference, see
+// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13.
+package pattern
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// Mode can be used to supply a number of options to the package's functions.
+// Not all functions change their behavior with all of the options below.
+type Mode uint
+
+type SyntaxError struct {
+ msg string
+ err error
+}
+
+func (e SyntaxError) Error() string { return e.msg }
+
+func (e SyntaxError) Unwrap() error { return e.err }
+
+const (
+ Shortest Mode = 1 << iota // prefer the shortest match.
+ Filenames // "*" and "?" don't match slashes; only "**" does
+ Braces // support "{a,b}" and "{1..4}"
+ EntireString // match the entire string using ^$ delimiters
+)
+
+var numRange = regexp.MustCompile(`^([+-]?\d+)\.\.([+-]?\d+)}`)
+
+// Regexp turns a shell pattern into a regular expression that can be used with
+// regexp.Compile. It will return an error if the input pattern was incorrect.
+// Otherwise, the returned expression can be passed to regexp.MustCompile.
+//
+// For example, Regexp(`foo*bar?`, true) returns `foo.*bar.`.
+//
+// Note that this function (and QuoteMeta) should not be directly used with file
+// paths if Windows is supported, as the path separator on that platform is the
+// same character as the escaping character for shell patterns.
+func Regexp(pat string, mode Mode) (string, error) {
+ any := false
+noopLoop:
+ for _, r := range pat {
+ switch r {
+ // including those that need escaping since they are
+ // regular expression metacharacters
+ case '*', '?', '[', '\\', '.', '+', '(', ')', '|',
+ ']', '{', '}', '^', '$':
+ any = true
+ break noopLoop
+ }
+ }
+ if !any && mode&EntireString == 0 { // short-cut without a string copy
+ return pat, nil
+ }
+ closingBraces := []int{}
+ var buf bytes.Buffer
+ // Enable matching `\n` with the `.` metacharacter as globs match `\n`
+ buf.WriteString("(?s)")
+ dotMeta := false
+ if mode&EntireString != 0 {
+ buf.WriteString("^")
+ }
+writeLoop:
+ for i := 0; i < len(pat); i++ {
+ switch c := pat[i]; c {
+ case '*':
+ if mode&Filenames != 0 {
+ if i++; i < len(pat) && pat[i] == '*' {
+ if i++; i < len(pat) && pat[i] == '/' {
+ buf.WriteString("(.*/|)")
+ dotMeta = true
+ } else {
+ buf.WriteString(".*")
+ dotMeta = true
+ i--
+ }
+ } else {
+ buf.WriteString("[^/]*")
+ i--
+ }
+ } else {
+ buf.WriteString(".*")
+ dotMeta = true
+ }
+ if mode&Shortest != 0 {
+ buf.WriteByte('?')
+ }
+ case '?':
+ if mode&Filenames != 0 {
+ buf.WriteString("[^/]")
+ } else {
+ buf.WriteByte('.')
+ dotMeta = true
+ }
+ case '\\':
+ if i++; i >= len(pat) {
+ return "", &SyntaxError{msg: `\ at end of pattern`}
+ }
+ buf.WriteString(regexp.QuoteMeta(string(pat[i])))
+ case '[':
+ name, err := charClass(pat[i:])
+ if err != nil {
+ return "", &SyntaxError{msg: "charClass invalid", err: err}
+ }
+ if name != "" {
+ buf.WriteString(name)
+ i += len(name) - 1
+ break
+ }
+ if mode&Filenames != 0 {
+ for _, c := range pat[i:] {
+ if c == ']' {
+ break
+ } else if c == '/' {
+ buf.WriteString("\\[")
+ continue writeLoop
+ }
+ }
+ }
+ buf.WriteByte(c)
+ if i++; i >= len(pat) {
+ return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
+ }
+ switch c = pat[i]; c {
+ case '!', '^':
+ buf.WriteByte('^')
+ if i++; i >= len(pat) {
+ return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
+ }
+ }
+ if c = pat[i]; c == ']' {
+ buf.WriteByte(']')
+ if i++; i >= len(pat) {
+ return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
+ }
+ }
+ rangeStart := byte(0)
+ loopBracket:
+ for ; i < len(pat); i++ {
+ c = pat[i]
+ buf.WriteByte(c)
+ switch c {
+ case '\\':
+ if i++; i < len(pat) {
+ buf.WriteByte(pat[i])
+ }
+ continue
+ case ']':
+ break loopBracket
+ }
+ if rangeStart != 0 && rangeStart > c {
+ return "", &SyntaxError{msg: fmt.Sprintf("invalid range: %c-%c", rangeStart, c)}
+ }
+ if c == '-' {
+ rangeStart = pat[i-1]
+ } else {
+ rangeStart = 0
+ }
+ }
+ if i >= len(pat) {
+ return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
+ }
+ case '{':
+ if mode&Braces == 0 {
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ break
+ }
+ innerLevel := 1
+ commas := false
+ peekBrace:
+ for j := i + 1; j < len(pat); j++ {
+ switch c := pat[j]; c {
+ case '{':
+ innerLevel++
+ case ',':
+ commas = true
+ case '\\':
+ j++
+ case '}':
+ if innerLevel--; innerLevel > 0 {
+ continue
+ }
+ if !commas {
+ break peekBrace
+ }
+ closingBraces = append(closingBraces, j)
+ buf.WriteString("(?:")
+ continue writeLoop
+ }
+ }
+ if match := numRange.FindStringSubmatch(pat[i+1:]); len(match) == 3 {
+ start, err1 := strconv.Atoi(match[1])
+ end, err2 := strconv.Atoi(match[2])
+ if err1 != nil || err2 != nil || start > end {
+ return "", &SyntaxError{msg: fmt.Sprintf("invalid range: %q", match[0])}
+ }
+ // TODO: can we do better here?
+ buf.WriteString("(?:")
+ for n := start; n <= end; n++ {
+ if n > start {
+ buf.WriteByte('|')
+ }
+ fmt.Fprintf(&buf, "%d", n)
+ }
+ buf.WriteByte(')')
+ i += len(match[0])
+ break
+ }
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ case ',':
+ if len(closingBraces) == 0 {
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ } else {
+ buf.WriteByte('|')
+ }
+ case '}':
+ if len(closingBraces) > 0 && closingBraces[len(closingBraces)-1] == i {
+ buf.WriteByte(')')
+ closingBraces = closingBraces[:len(closingBraces)-1]
+ } else {
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ }
+ default:
+ if c > 128 {
+ buf.WriteByte(c)
+ } else {
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ }
+ }
+ }
+ if mode&EntireString != 0 {
+ buf.WriteString("$")
+ }
+ // No `.` metacharacters were used, so don't return the flag.
+ if !dotMeta {
+ return string(buf.Bytes()[4:]), nil
+ }
+ return buf.String(), nil
+}
+
+func charClass(s string) (string, error) {
+ if strings.HasPrefix(s, "[[.") || strings.HasPrefix(s, "[[=") {
+ return "", fmt.Errorf("collating features not available")
+ }
+ if !strings.HasPrefix(s, "[[:") {
+ return "", nil
+ }
+ name := s[3:]
+ end := strings.Index(name, ":]]")
+ if end < 0 {
+ return "", fmt.Errorf("[[: was not matched with a closing :]]")
+ }
+ name = name[:end]
+ switch name {
+ case "alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph",
+ "lower", "print", "punct", "space", "upper", "word", "xdigit":
+ default:
+ return "", fmt.Errorf("invalid character class: %q", name)
+ }
+ return s[:len(name)+6], nil
+}
+
+// HasMeta returns whether a string contains any unescaped pattern
+// metacharacters: '*', '?', or '['. When the function returns false, the given
+// pattern can only match at most one string.
+//
+// For example, HasMeta(`foo\*bar`) returns false, but HasMeta(`foo*bar`)
+// returns true.
+//
+// This can be useful to avoid extra work, like TranslatePattern. Note that this
+// function cannot be used to avoid QuotePattern, as backslashes are quoted by
+// that function but ignored here.
+func HasMeta(pat string, mode Mode) bool {
+ for i := 0; i < len(pat); i++ {
+ switch pat[i] {
+ case '\\':
+ i++
+ case '*', '?', '[':
+ return true
+ case '{':
+ if mode&Braces != 0 {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// QuoteMeta returns a string that quotes all pattern metacharacters in the
+// given text. The returned string is a pattern that matches the literal text.
+//
+// For example, QuoteMeta(`foo*bar?`) returns `foo\*bar\?`.
+func QuoteMeta(pat string, mode Mode) string {
+ any := false
+loop:
+ for _, r := range pat {
+ switch r {
+ case '{':
+ if mode&Braces == 0 {
+ continue
+ }
+ fallthrough
+ case '*', '?', '[', '\\':
+ any = true
+ break loop
+ }
+ }
+ if !any { // short-cut without a string copy
+ return pat
+ }
+ var buf bytes.Buffer
+ for _, r := range pat {
+ switch r {
+ case '*', '?', '[', '\\':
+ buf.WriteByte('\\')
+ case '{':
+ if mode&Braces != 0 {
+ buf.WriteByte('\\')
+ }
+ }
+ buf.WriteRune(r)
+ }
+ return buf.String()
+}
diff --git a/vendor/mvdan.cc/sh/v3/shell/doc.go b/vendor/mvdan.cc/sh/v3/shell/doc.go
new file mode 100644
index 00000000..81e0c2f7
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/shell/doc.go
@@ -0,0 +1,14 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+// Package shell contains high-level features that use the syntax, expand, and
+// interp packages under the hood.
+//
+// Please note that this package uses POSIX Shell syntax. As such, path names on
+// Windows need to use double backslashes or be within single quotes when given
+// to functions like Fields. For example:
+//
+// shell.Fields("echo /foo/bar") // on Unix-like
+// shell.Fields("echo C:\\foo\\bar") // on Windows
+// shell.Fields("echo 'C:\foo\bar'") // on Windows, with quotes
+package shell
diff --git a/vendor/mvdan.cc/sh/v3/shell/expand.go b/vendor/mvdan.cc/sh/v3/shell/expand.go
new file mode 100644
index 00000000..e286c0a9
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/shell/expand.go
@@ -0,0 +1,63 @@
+// Copyright (c) 2018, Daniel Martí
+// See LICENSE for licensing information
+
+package shell
+
+import (
+ "os"
+ "strings"
+
+ "mvdan.cc/sh/v3/expand"
+ "mvdan.cc/sh/v3/syntax"
+)
+
+// Expand performs shell expansion on s as if it were within double quotes,
+// using env to resolve variables. This includes parameter expansion, arithmetic
+// expansion, and quote removal.
+//
+// If env is nil, the current environment variables are used. Empty variables
+// are treated as unset; to support variables which are set but empty, use the
+// expand package directly.
+//
+// Command substitutions like $(echo foo) aren't supported to avoid running
+// arbitrary code. To support those, use an interpreter with the expand package.
+//
+// An error will be reported if the input string had invalid syntax.
+func Expand(s string, env func(string) string) (string, error) {
+ p := syntax.NewParser()
+ word, err := p.Document(strings.NewReader(s))
+ if err != nil {
+ return "", err
+ }
+ if env == nil {
+ env = os.Getenv
+ }
+ cfg := &expand.Config{Env: expand.FuncEnviron(env)}
+ return expand.Document(cfg, word)
+}
+
+// Fields performs shell expansion on s as if it were a command's arguments,
+// using env to resolve variables. It is similar to Expand, but includes brace
+// expansion, tilde expansion, and globbing.
+//
+// If env is nil, the current environment variables are used. Empty variables
+// are treated as unset; to support variables which are set but empty, use the
+// expand package directly.
+//
+// An error will be reported if the input string had invalid syntax.
+func Fields(s string, env func(string) string) ([]string, error) {
+ p := syntax.NewParser()
+ var words []*syntax.Word
+ err := p.Words(strings.NewReader(s), func(w *syntax.Word) bool {
+ words = append(words, w)
+ return true
+ })
+ if err != nil {
+ return nil, err
+ }
+ if env == nil {
+ env = os.Getenv
+ }
+ cfg := &expand.Config{Env: expand.FuncEnviron(env)}
+ return expand.Fields(cfg, words...)
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/braces.go b/vendor/mvdan.cc/sh/v3/syntax/braces.go
new file mode 100644
index 00000000..dca854fd
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/braces.go
@@ -0,0 +1,177 @@
+// Copyright (c) 2018, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import "strconv"
+
+var (
+ litLeftBrace = &Lit{Value: "{"}
+ litComma = &Lit{Value: ","}
+ litDots = &Lit{Value: ".."}
+ litRightBrace = &Lit{Value: "}"}
+)
+
+// SplitBraces parses brace expansions within a word's literal parts. If any
+// valid brace expansions are found, they are replaced with BraceExp nodes, and
+// the function returns true. Otherwise, the word is left untouched and the
+// function returns false.
+//
+// For example, a literal word "foo{bar,baz}" will result in a word containing
+// the literal "foo", and a brace expansion with the elements "bar" and "baz".
+//
+// It does not return an error; malformed brace expansions are simply skipped.
+// For example, the literal word "a{b" is left unchanged.
+func SplitBraces(word *Word) bool {
+ any := false
+ top := &Word{}
+ acc := top
+ var cur *BraceExp
+ open := []*BraceExp{}
+
+ pop := func() *BraceExp {
+ old := cur
+ open = open[:len(open)-1]
+ if len(open) == 0 {
+ cur = nil
+ acc = top
+ } else {
+ cur = open[len(open)-1]
+ acc = cur.Elems[len(cur.Elems)-1]
+ }
+ return old
+ }
+ addLit := func(lit *Lit) {
+ acc.Parts = append(acc.Parts, lit)
+ }
+
+ for _, wp := range word.Parts {
+ lit, ok := wp.(*Lit)
+ if !ok {
+ acc.Parts = append(acc.Parts, wp)
+ continue
+ }
+ last := 0
+ for j := 0; j < len(lit.Value); j++ {
+ addlitidx := func() {
+ if last == j {
+ return // empty lit
+ }
+ l2 := *lit
+ l2.Value = l2.Value[last:j]
+ addLit(&l2)
+ }
+ switch lit.Value[j] {
+ case '{':
+ addlitidx()
+ acc = &Word{}
+ cur = &BraceExp{Elems: []*Word{acc}}
+ open = append(open, cur)
+ case ',':
+ if cur == nil {
+ continue
+ }
+ addlitidx()
+ acc = &Word{}
+ cur.Elems = append(cur.Elems, acc)
+ case '.':
+ if cur == nil {
+ continue
+ }
+ if j+1 >= len(lit.Value) || lit.Value[j+1] != '.' {
+ continue
+ }
+ addlitidx()
+ cur.Sequence = true
+ acc = &Word{}
+ cur.Elems = append(cur.Elems, acc)
+ j++
+ case '}':
+ if cur == nil {
+ continue
+ }
+ any = true
+ addlitidx()
+ br := pop()
+ if len(br.Elems) == 1 {
+ // return {x} to a non-brace
+ addLit(litLeftBrace)
+ acc.Parts = append(acc.Parts, br.Elems[0].Parts...)
+ addLit(litRightBrace)
+ break
+ }
+ if !br.Sequence {
+ acc.Parts = append(acc.Parts, br)
+ break
+ }
+ var chars [2]bool
+ broken := false
+ for i, elem := range br.Elems[:2] {
+ val := elem.Lit()
+ if _, err := strconv.Atoi(val); err == nil {
+ } else if len(val) == 1 &&
+ 'a' <= val[0] && val[0] <= 'z' {
+ chars[i] = true
+ } else {
+ broken = true
+ }
+ }
+ if len(br.Elems) == 3 {
+ // increment must be a number
+ val := br.Elems[2].Lit()
+ if _, err := strconv.Atoi(val); err != nil {
+ broken = true
+ }
+ }
+ // are start and end both chars or
+ // non-chars?
+ if chars[0] != chars[1] {
+ broken = true
+ }
+ if !broken {
+ acc.Parts = append(acc.Parts, br)
+ break
+ }
+ // return broken {x..y[..incr]} to a non-brace
+ addLit(litLeftBrace)
+ for i, elem := range br.Elems {
+ if i > 0 {
+ addLit(litDots)
+ }
+ acc.Parts = append(acc.Parts, elem.Parts...)
+ }
+ addLit(litRightBrace)
+ default:
+ continue
+ }
+ last = j + 1
+ }
+ if last == 0 {
+ addLit(lit)
+ } else {
+ left := *lit
+ left.Value = left.Value[last:]
+ addLit(&left)
+ }
+ }
+ if !any {
+ return false
+ }
+ // open braces that were never closed fall back to non-braces
+ for acc != top {
+ br := pop()
+ addLit(litLeftBrace)
+ for i, elem := range br.Elems {
+ if i > 0 {
+ if br.Sequence {
+ addLit(litDots)
+ } else {
+ addLit(litComma)
+ }
+ }
+ acc.Parts = append(acc.Parts, elem.Parts...)
+ }
+ }
+ *word = *top
+ return true
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/canonical.sh b/vendor/mvdan.cc/sh/v3/syntax/canonical.sh
new file mode 100644
index 00000000..012f48dd
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/canonical.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# separate comment
+
+! foo bar >a &
+
+foo() { bar; }
+
+{
+ var1="some long value" # var1 comment
+ var2=short # var2 comment
+}
+
+if foo; then bar; fi
+
+for foo in a b c; do
+ bar
+done
+
+case $foo in
+a) A ;;
+b)
+ B
+ ;;
+esac
+
+foo | bar
+foo &&
+ $(bar) &&
+ (more)
+
+foo 2>&1
+foo <<-EOF
+ bar
+EOF
+
+$((3 + 4))
diff --git a/vendor/mvdan.cc/sh/v3/syntax/doc.go b/vendor/mvdan.cc/sh/v3/syntax/doc.go
new file mode 100644
index 00000000..5c6275e4
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+// Package syntax implements parsing and formatting of shell programs.
+// It supports POSIX Shell, Bash, and mksh.
+package syntax
diff --git a/vendor/mvdan.cc/sh/v3/syntax/lexer.go b/vendor/mvdan.cc/sh/v3/syntax/lexer.go
new file mode 100644
index 00000000..583abb61
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/lexer.go
@@ -0,0 +1,1203 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "bytes"
+ "io"
+ "unicode/utf8"
+)
+
+// bytes that form or start a token
+func regOps(r rune) bool {
+ switch r {
+ case ';', '"', '\'', '(', ')', '$', '|', '&', '>', '<', '`':
+ return true
+ }
+ return false
+}
+
+// tokenize these inside parameter expansions
+func paramOps(r rune) bool {
+ switch r {
+ case '}', '#', '!', ':', '-', '+', '=', '?', '%', '[', ']', '/', '^',
+ ',', '@', '*':
+ return true
+ }
+ return false
+}
+
+// these start a parameter expansion name
+func paramNameOp(r rune) bool {
+ switch r {
+ case '}', ':', '+', '=', '%', '[', ']', '/', '^', ',':
+ return false
+ }
+ return true
+}
+
+// tokenize these inside arithmetic expansions
+func arithmOps(r rune) bool {
+ switch r {
+ case '+', '-', '!', '~', '*', '/', '%', '(', ')', '^', '<', '>', ':', '=',
+ ',', '?', '|', '&', '[', ']', '#':
+ return true
+ }
+ return false
+}
+
+func bquoteEscaped(b byte) bool {
+ switch b {
+ case '$', '`', '\\':
+ return true
+ }
+ return false
+}
+
+const escNewl rune = utf8.RuneSelf + 1
+
+func (p *Parser) rune() rune {
+ if p.r == '\n' || p.r == escNewl {
+ // p.r instead of b so that newline
+ // character positions don't have col 0.
+ if p.line++; p.line > lineMax {
+ p.lineOverflow = true
+ }
+ p.col = 0
+ p.colOverflow = false
+ }
+ if p.col += p.w; p.col > colMax {
+ p.colOverflow = true
+ }
+ bquotes := 0
+retry:
+ if p.bsp < len(p.bs) {
+ if b := p.bs[p.bsp]; b < utf8.RuneSelf {
+ p.bsp++
+ if b == '\x00' {
+ // Ignore null bytes while parsing, like bash.
+ goto retry
+ }
+ if b == '\\' {
+ if p.r == '\\' {
+ } else if p.peekByte('\n') {
+ p.bsp++
+ p.w, p.r = 1, escNewl
+ return escNewl
+ } else if p.peekBytes("\r\n") {
+ p.bsp += 2
+ p.w, p.r = 2, escNewl
+ return escNewl
+ }
+ if p.openBquotes > 0 && bquotes < p.openBquotes &&
+ p.bsp < len(p.bs) && bquoteEscaped(p.bs[p.bsp]) {
+ bquotes++
+ goto retry
+ }
+ }
+ if b == '`' {
+ p.lastBquoteEsc = bquotes
+ }
+ if p.litBs != nil {
+ p.litBs = append(p.litBs, b)
+ }
+ p.w, p.r = 1, rune(b)
+ return p.r
+ }
+ if !utf8.FullRune(p.bs[p.bsp:]) {
+ // we need more bytes to read a full non-ascii rune
+ p.fill()
+ }
+ var w int
+ p.r, w = utf8.DecodeRune(p.bs[p.bsp:])
+ if p.litBs != nil {
+ p.litBs = append(p.litBs, p.bs[p.bsp:p.bsp+w]...)
+ }
+ p.bsp += w
+ if p.r == utf8.RuneError && w == 1 {
+ p.posErr(p.nextPos(), "invalid UTF-8 encoding")
+ }
+ p.w = w
+ } else {
+ if p.r == utf8.RuneSelf {
+ } else if p.fill(); p.bs == nil {
+ p.bsp++
+ p.r = utf8.RuneSelf
+ p.w = 1
+ } else {
+ goto retry
+ }
+ }
+ return p.r
+}
+
+// fill reads more bytes from the input src into readBuf. Any bytes that
+// had not yet been used at the end of the buffer are slid into the
+// beginning of the buffer.
+func (p *Parser) fill() {
+ p.offs += p.bsp
+ left := len(p.bs) - p.bsp
+ copy(p.readBuf[:left], p.readBuf[p.bsp:])
+readAgain:
+ n, err := 0, p.readErr
+ if err == nil {
+ n, err = p.src.Read(p.readBuf[left:])
+ p.readErr = err
+ }
+ if n == 0 {
+ if err == nil {
+ goto readAgain
+ }
+ // don't use p.errPass as we don't want to overwrite p.tok
+ if err != io.EOF {
+ p.err = err
+ }
+ if left > 0 {
+ p.bs = p.readBuf[:left]
+ } else {
+ p.bs = nil
+ }
+ } else {
+ p.bs = p.readBuf[:left+n]
+ }
+ p.bsp = 0
+}
+
+func (p *Parser) nextKeepSpaces() {
+ r := p.r
+ if p.quote != hdocBody && p.quote != hdocBodyTabs {
+ // Heredocs handle escaped newlines in a special way, but others
+ // do not.
+ for r == escNewl {
+ r = p.rune()
+ }
+ }
+ p.pos = p.nextPos()
+ switch p.quote {
+ case paramExpRepl:
+ switch r {
+ case '}', '/':
+ p.tok = p.paramToken(r)
+ case '`', '"', '$', '\'':
+ p.tok = p.regToken(r)
+ default:
+ p.advanceLitOther(r)
+ }
+ case dblQuotes:
+ switch r {
+ case '`', '"', '$':
+ p.tok = p.dqToken(r)
+ default:
+ p.advanceLitDquote(r)
+ }
+ case hdocBody, hdocBodyTabs:
+ switch r {
+ case '`', '$':
+ p.tok = p.dqToken(r)
+ default:
+ p.advanceLitHdoc(r)
+ }
+ default: // paramExpExp:
+ switch r {
+ case '}':
+ p.tok = p.paramToken(r)
+ case '`', '"', '$', '\'':
+ p.tok = p.regToken(r)
+ default:
+ p.advanceLitOther(r)
+ }
+ }
+ if p.err != nil && p.tok != _EOF {
+ p.tok = _EOF
+ }
+}
+
+func (p *Parser) next() {
+ if p.r == utf8.RuneSelf {
+ p.tok = _EOF
+ return
+ }
+ p.spaced = false
+ if p.quote&allKeepSpaces != 0 {
+ p.nextKeepSpaces()
+ return
+ }
+ r := p.r
+ for r == escNewl {
+ r = p.rune()
+ }
+skipSpace:
+ for {
+ switch r {
+ case utf8.RuneSelf:
+ p.tok = _EOF
+ return
+ case escNewl:
+ r = p.rune()
+ case ' ', '\t', '\r':
+ p.spaced = true
+ r = p.rune()
+ case '\n':
+ if p.tok == _Newl {
+ // merge consecutive newline tokens
+ r = p.rune()
+ continue
+ }
+ p.spaced = true
+ p.tok = _Newl
+ if p.quote != hdocWord && len(p.heredocs) > p.buriedHdocs {
+ p.doHeredocs()
+ }
+ return
+ default:
+ break skipSpace
+ }
+ }
+ if p.stopAt != nil && (p.spaced || p.tok == illegalTok || p.stopToken()) {
+ w := utf8.RuneLen(r)
+ if bytes.HasPrefix(p.bs[p.bsp-w:], p.stopAt) {
+ p.r = utf8.RuneSelf
+ p.w = 1
+ p.tok = _EOF
+ return
+ }
+ }
+ p.pos = p.nextPos()
+ switch {
+ case p.quote&allRegTokens != 0:
+ switch r {
+ case ';', '"', '\'', '(', ')', '$', '|', '&', '>', '<', '`':
+ p.tok = p.regToken(r)
+ case '#':
+ r = p.rune()
+ p.newLit(r)
+ runeLoop:
+ for {
+ switch r {
+ case '\n', utf8.RuneSelf:
+ break runeLoop
+ case escNewl:
+ p.litBs = append(p.litBs, '\\', '\n')
+ break runeLoop
+ case '`':
+ if p.backquoteEnd() {
+ break runeLoop
+ }
+ }
+ r = p.rune()
+ }
+ if p.keepComments {
+ *p.curComs = append(*p.curComs, Comment{
+ Hash: p.pos,
+ Text: p.endLit(),
+ })
+ } else {
+ p.litBs = nil
+ }
+ p.next()
+ case '[', '=':
+ if p.quote == arrayElems {
+ p.tok = p.paramToken(r)
+ } else {
+ p.advanceLitNone(r)
+ }
+ case '?', '*', '+', '@', '!':
+ if p.extendedGlob() {
+ switch r {
+ case '?':
+ p.tok = globQuest
+ case '*':
+ p.tok = globStar
+ case '+':
+ p.tok = globPlus
+ case '@':
+ p.tok = globAt
+ default: // '!'
+ p.tok = globExcl
+ }
+ p.rune()
+ p.rune()
+ } else {
+ p.advanceLitNone(r)
+ }
+ default:
+ p.advanceLitNone(r)
+ }
+ case p.quote&allArithmExpr != 0 && arithmOps(r):
+ p.tok = p.arithmToken(r)
+ case p.quote&allParamExp != 0 && paramOps(r):
+ p.tok = p.paramToken(r)
+ case p.quote == testExprRegexp:
+ if !p.rxFirstPart && p.spaced {
+ p.quote = noState
+ goto skipSpace
+ }
+ p.rxFirstPart = false
+ switch r {
+ case ';', '"', '\'', '$', '&', '>', '<', '`':
+ p.tok = p.regToken(r)
+ case ')':
+ if p.rxOpenParens > 0 {
+ // continuation of open paren
+ p.advanceLitRe(r)
+ } else {
+ p.tok = rightParen
+ p.quote = noState
+ p.rune() // we are tokenizing manually
+ }
+ default: // including '(', '|'
+ p.advanceLitRe(r)
+ }
+ case regOps(r):
+ p.tok = p.regToken(r)
+ default:
+ p.advanceLitOther(r)
+ }
+ if p.err != nil && p.tok != _EOF {
+ p.tok = _EOF
+ }
+}
+
+// extendedGlob determines whether we're parsing a Bash extended globbing expression.
+// For example, whether `*` or `@` are followed by `(` to form `@(foo)`.
+func (p *Parser) extendedGlob() bool {
+ if p.val == "function" {
+ return false
+ }
+ if p.peekByte('(') {
+ // NOTE: empty pattern list is a valid globbing syntax like `@()`,
+ // but we'll operate on the "likelihood" that it is a function;
+ // only tokenize if its a non-empty pattern list.
+ // We do this after peeking for just one byte, so that the input `echo *`
+ // followed by a newline does not hang an interactive shell parser until
+ // another byte is input.
+ if p.peekBytes("()") {
+ return false
+ }
+ return true
+ }
+ return false
+}
+
+func (p *Parser) peekBytes(s string) bool {
+ peekEnd := p.bsp + len(s)
+ // TODO: This should loop for slow readers, e.g. those providing one byte at
+ // a time. Use a loop and test it with testing/iotest.OneByteReader.
+ if peekEnd > len(p.bs) {
+ p.fill()
+ }
+ return peekEnd <= len(p.bs) && bytes.HasPrefix(p.bs[p.bsp:peekEnd], []byte(s))
+}
+
+func (p *Parser) peekByte(b byte) bool {
+ if p.bsp == len(p.bs) {
+ p.fill()
+ }
+ return p.bsp < len(p.bs) && p.bs[p.bsp] == b
+}
+
+func (p *Parser) regToken(r rune) token {
+ switch r {
+ case '\'':
+ if p.openBquotes > 0 {
+ // bury openBquotes
+ p.buriedBquotes = p.openBquotes
+ p.openBquotes = 0
+ }
+ p.rune()
+ return sglQuote
+ case '"':
+ p.rune()
+ return dblQuote
+ case '`':
+ // Don't call p.rune, as we need to work out p.openBquotes to
+ // properly handle backslashes in the lexer.
+ return bckQuote
+ case '&':
+ switch p.rune() {
+ case '&':
+ p.rune()
+ return andAnd
+ case '>':
+ if p.lang == LangPOSIX {
+ break
+ }
+ if p.rune() == '>' {
+ p.rune()
+ return appAll
+ }
+ return rdrAll
+ }
+ return and
+ case '|':
+ switch p.rune() {
+ case '|':
+ p.rune()
+ return orOr
+ case '&':
+ if p.lang == LangPOSIX {
+ break
+ }
+ p.rune()
+ return orAnd
+ }
+ return or
+ case '$':
+ switch p.rune() {
+ case '\'':
+ if p.lang == LangPOSIX {
+ break
+ }
+ p.rune()
+ return dollSglQuote
+ case '"':
+ if p.lang == LangPOSIX {
+ break
+ }
+ p.rune()
+ return dollDblQuote
+ case '{':
+ p.rune()
+ return dollBrace
+ case '[':
+ if !p.lang.isBash() || p.quote == paramExpName {
+ // latter to not tokenise ${$[@]} as $[
+ break
+ }
+ p.rune()
+ return dollBrack
+ case '(':
+ if p.rune() == '(' {
+ p.rune()
+ return dollDblParen
+ }
+ return dollParen
+ }
+ return dollar
+ case '(':
+ if p.rune() == '(' && p.lang != LangPOSIX && p.quote != testExpr {
+ p.rune()
+ return dblLeftParen
+ }
+ return leftParen
+ case ')':
+ p.rune()
+ return rightParen
+ case ';':
+ switch p.rune() {
+ case ';':
+ if p.rune() == '&' && p.lang.isBash() {
+ p.rune()
+ return dblSemiAnd
+ }
+ return dblSemicolon
+ case '&':
+ if p.lang == LangPOSIX {
+ break
+ }
+ p.rune()
+ return semiAnd
+ case '|':
+ if p.lang != LangMirBSDKorn {
+ break
+ }
+ p.rune()
+ return semiOr
+ }
+ return semicolon
+ case '<':
+ switch p.rune() {
+ case '<':
+ if r = p.rune(); r == '-' {
+ p.rune()
+ return dashHdoc
+ } else if r == '<' {
+ p.rune()
+ return wordHdoc
+ }
+ return hdoc
+ case '>':
+ p.rune()
+ return rdrInOut
+ case '&':
+ p.rune()
+ return dplIn
+ case '(':
+ if !p.lang.isBash() {
+ break
+ }
+ p.rune()
+ return cmdIn
+ }
+ return rdrIn
+ default: // '>'
+ switch p.rune() {
+ case '>':
+ p.rune()
+ return appOut
+ case '&':
+ p.rune()
+ return dplOut
+ case '|':
+ p.rune()
+ return clbOut
+ case '(':
+ if !p.lang.isBash() {
+ break
+ }
+ p.rune()
+ return cmdOut
+ }
+ return rdrOut
+ }
+}
+
+func (p *Parser) dqToken(r rune) token {
+ switch r {
+ case '"':
+ p.rune()
+ return dblQuote
+ case '`':
+ // Don't call p.rune, as we need to work out p.openBquotes to
+ // properly handle backslashes in the lexer.
+ return bckQuote
+ default: // '$'
+ switch p.rune() {
+ case '{':
+ p.rune()
+ return dollBrace
+ case '[':
+ if !p.lang.isBash() {
+ break
+ }
+ p.rune()
+ return dollBrack
+ case '(':
+ if p.rune() == '(' {
+ p.rune()
+ return dollDblParen
+ }
+ return dollParen
+ }
+ return dollar
+ }
+}
+
+func (p *Parser) paramToken(r rune) token {
+ switch r {
+ case '}':
+ p.rune()
+ return rightBrace
+ case ':':
+ switch p.rune() {
+ case '+':
+ p.rune()
+ return colPlus
+ case '-':
+ p.rune()
+ return colMinus
+ case '?':
+ p.rune()
+ return colQuest
+ case '=':
+ p.rune()
+ return colAssgn
+ }
+ return colon
+ case '+':
+ p.rune()
+ return plus
+ case '-':
+ p.rune()
+ return minus
+ case '?':
+ p.rune()
+ return quest
+ case '=':
+ p.rune()
+ return assgn
+ case '%':
+ if p.rune() == '%' {
+ p.rune()
+ return dblPerc
+ }
+ return perc
+ case '#':
+ if p.rune() == '#' {
+ p.rune()
+ return dblHash
+ }
+ return hash
+ case '!':
+ p.rune()
+ return exclMark
+ case '[':
+ p.rune()
+ return leftBrack
+ case ']':
+ p.rune()
+ return rightBrack
+ case '/':
+ if p.rune() == '/' && p.quote != paramExpRepl {
+ p.rune()
+ return dblSlash
+ }
+ return slash
+ case '^':
+ if p.rune() == '^' {
+ p.rune()
+ return dblCaret
+ }
+ return caret
+ case ',':
+ if p.rune() == ',' {
+ p.rune()
+ return dblComma
+ }
+ return comma
+ case '@':
+ p.rune()
+ return at
+ default: // '*'
+ p.rune()
+ return star
+ }
+}
+
+func (p *Parser) arithmToken(r rune) token {
+ switch r {
+ case '!':
+ if p.rune() == '=' {
+ p.rune()
+ return nequal
+ }
+ return exclMark
+ case '=':
+ if p.rune() == '=' {
+ p.rune()
+ return equal
+ }
+ return assgn
+ case '~':
+ p.rune()
+ return tilde
+ case '(':
+ p.rune()
+ return leftParen
+ case ')':
+ p.rune()
+ return rightParen
+ case '&':
+ switch p.rune() {
+ case '&':
+ p.rune()
+ return andAnd
+ case '=':
+ p.rune()
+ return andAssgn
+ }
+ return and
+ case '|':
+ switch p.rune() {
+ case '|':
+ p.rune()
+ return orOr
+ case '=':
+ p.rune()
+ return orAssgn
+ }
+ return or
+ case '<':
+ switch p.rune() {
+ case '<':
+ if p.rune() == '=' {
+ p.rune()
+ return shlAssgn
+ }
+ return hdoc
+ case '=':
+ p.rune()
+ return lequal
+ }
+ return rdrIn
+ case '>':
+ switch p.rune() {
+ case '>':
+ if p.rune() == '=' {
+ p.rune()
+ return shrAssgn
+ }
+ return appOut
+ case '=':
+ p.rune()
+ return gequal
+ }
+ return rdrOut
+ case '+':
+ switch p.rune() {
+ case '+':
+ p.rune()
+ return addAdd
+ case '=':
+ p.rune()
+ return addAssgn
+ }
+ return plus
+ case '-':
+ switch p.rune() {
+ case '-':
+ p.rune()
+ return subSub
+ case '=':
+ p.rune()
+ return subAssgn
+ }
+ return minus
+ case '%':
+ if p.rune() == '=' {
+ p.rune()
+ return remAssgn
+ }
+ return perc
+ case '*':
+ switch p.rune() {
+ case '*':
+ p.rune()
+ return power
+ case '=':
+ p.rune()
+ return mulAssgn
+ }
+ return star
+ case '/':
+ if p.rune() == '=' {
+ p.rune()
+ return quoAssgn
+ }
+ return slash
+ case '^':
+ if p.rune() == '=' {
+ p.rune()
+ return xorAssgn
+ }
+ return caret
+ case '[':
+ p.rune()
+ return leftBrack
+ case ']':
+ p.rune()
+ return rightBrack
+ case ',':
+ p.rune()
+ return comma
+ case '?':
+ p.rune()
+ return quest
+ case ':':
+ p.rune()
+ return colon
+ default: // '#'
+ p.rune()
+ return hash
+ }
+}
+
+func (p *Parser) newLit(r rune) {
+ switch {
+ case r < utf8.RuneSelf:
+ p.litBs = p.litBuf[:1]
+ p.litBs[0] = byte(r)
+ case r > escNewl:
+ w := utf8.RuneLen(r)
+ p.litBs = append(p.litBuf[:0], p.bs[p.bsp-w:p.bsp]...)
+ default:
+ // don't let r == utf8.RuneSelf go to the second case as RuneLen
+ // would return -1
+ p.litBs = p.litBuf[:0]
+ }
+}
+
+func (p *Parser) endLit() (s string) {
+ if p.r == utf8.RuneSelf || p.r == escNewl {
+ s = string(p.litBs)
+ } else {
+ s = string(p.litBs[:len(p.litBs)-p.w])
+ }
+ p.litBs = nil
+ return
+}
+
+func (p *Parser) isLitRedir() bool {
+ lit := p.litBs[:len(p.litBs)-1]
+ if lit[0] == '{' && lit[len(lit)-1] == '}' {
+ return ValidName(string(lit[1 : len(lit)-1]))
+ }
+ for _, b := range lit {
+ switch b {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+func (p *Parser) advanceNameCont(r rune) {
+ // we know that r is a letter or underscore
+loop:
+ for p.newLit(r); r != utf8.RuneSelf; r = p.rune() {
+ switch {
+ case 'a' <= r && r <= 'z':
+ case 'A' <= r && r <= 'Z':
+ case r == '_':
+ case '0' <= r && r <= '9':
+ case r == escNewl:
+ default:
+ break loop
+ }
+ }
+ p.tok, p.val = _LitWord, p.endLit()
+}
+
+func (p *Parser) advanceLitOther(r rune) {
+ tok := _LitWord
+loop:
+ for p.newLit(r); r != utf8.RuneSelf; r = p.rune() {
+ switch r {
+ case '\\': // escaped byte follows
+ p.rune()
+ case '\'', '"', '`', '$':
+ tok = _Lit
+ break loop
+ case '}':
+ if p.quote&allParamExp != 0 {
+ break loop
+ }
+ case '/':
+ if p.quote != paramExpExp {
+ break loop
+ }
+ case ':', '=', '%', '^', ',', '?', '!', '~', '*':
+ if p.quote&allArithmExpr != 0 || p.quote == paramExpName {
+ break loop
+ }
+ case '[', ']':
+ if p.lang != LangPOSIX && p.quote&allArithmExpr != 0 {
+ break loop
+ }
+ fallthrough
+ case '#', '@':
+ if p.quote&allParamReg != 0 {
+ break loop
+ }
+ case '+', '-', ' ', '\t', ';', '&', '>', '<', '|', '(', ')', '\n', '\r':
+ if p.quote&allKeepSpaces == 0 {
+ break loop
+ }
+ }
+ }
+ p.tok, p.val = tok, p.endLit()
+}
+
+func (p *Parser) advanceLitNone(r rune) {
+ p.eqlOffs = -1
+ tok := _LitWord
+loop:
+ for p.newLit(r); r != utf8.RuneSelf; r = p.rune() {
+ switch r {
+ case ' ', '\t', '\n', '\r', '&', '|', ';', '(', ')':
+ break loop
+ case '\\': // escaped byte follows
+ p.rune()
+ case '>', '<':
+ if p.peekByte('(') {
+ tok = _Lit
+ } else if p.isLitRedir() {
+ tok = _LitRedir
+ }
+ break loop
+ case '`':
+ if p.quote != subCmdBckquo {
+ tok = _Lit
+ }
+ break loop
+ case '"', '\'', '$':
+ tok = _Lit
+ break loop
+ case '?', '*', '+', '@', '!':
+ if p.extendedGlob() {
+ tok = _Lit
+ break loop
+ }
+ case '=':
+ if p.eqlOffs < 0 {
+ p.eqlOffs = len(p.litBs) - 1
+ }
+ case '[':
+ if p.lang != LangPOSIX && len(p.litBs) > 1 && p.litBs[0] != '[' {
+ tok = _Lit
+ break loop
+ }
+ }
+ }
+ p.tok, p.val = tok, p.endLit()
+}
+
+func (p *Parser) advanceLitDquote(r rune) {
+ tok := _LitWord
+loop:
+ for p.newLit(r); r != utf8.RuneSelf; r = p.rune() {
+ switch r {
+ case '"':
+ break loop
+ case '\\': // escaped byte follows
+ p.rune()
+ case escNewl, '`', '$':
+ tok = _Lit
+ break loop
+ }
+ }
+ p.tok, p.val = tok, p.endLit()
+}
+
+func (p *Parser) advanceLitHdoc(r rune) {
+ // Unlike the rest of nextKeepSpaces quote states, we handle escaped
+ // newlines here. If lastTok==_Lit, then we know we're following an
+ // escaped newline, so the first line can't end the heredoc.
+ lastTok := p.tok
+ for r == escNewl {
+ r = p.rune()
+ lastTok = _Lit
+ }
+ p.pos = p.nextPos()
+
+ p.tok = _Lit
+ p.newLit(r)
+ if p.quote == hdocBodyTabs {
+ for r == '\t' {
+ r = p.rune()
+ }
+ }
+ lStart := len(p.litBs) - 1
+ stop := p.hdocStops[len(p.hdocStops)-1]
+ for ; ; r = p.rune() {
+ switch r {
+ case escNewl, '$':
+ p.val = p.endLit()
+ return
+ case '\\': // escaped byte follows
+ p.rune()
+ case '`':
+ if !p.backquoteEnd() {
+ p.val = p.endLit()
+ return
+ }
+ fallthrough
+ case '\n', utf8.RuneSelf:
+ if p.parsingDoc {
+ if r == utf8.RuneSelf {
+ p.tok = _LitWord
+ p.val = p.endLit()
+ return
+ }
+ } else if lStart == 0 && lastTok == _Lit {
+ // This line starts right after an escaped
+ // newline, so it should never end the heredoc.
+ } else if lStart >= 0 {
+ // Compare the current line with the stop word.
+ line := p.litBs[lStart:]
+ if r != utf8.RuneSelf && len(line) > 0 {
+ line = line[:len(line)-1] // minus trailing character
+ }
+ if bytes.Equal(line, stop) {
+ p.tok = _LitWord
+ p.val = p.endLit()[:lStart]
+ if p.val == "" {
+ p.tok = _Newl
+ }
+ p.hdocStops[len(p.hdocStops)-1] = nil
+ return
+ }
+ }
+ if r != '\n' {
+ return // hit an unexpected EOF or closing backquote
+ }
+ if p.quote == hdocBodyTabs {
+ for p.peekByte('\t') {
+ p.rune()
+ }
+ }
+ lStart = len(p.litBs)
+ }
+ }
+}
+
+func (p *Parser) quotedHdocWord() *Word {
+ r := p.r
+ p.newLit(r)
+ pos := p.nextPos()
+ stop := p.hdocStops[len(p.hdocStops)-1]
+ for ; ; r = p.rune() {
+ if r == utf8.RuneSelf {
+ return nil
+ }
+ if p.quote == hdocBodyTabs {
+ for r == '\t' {
+ r = p.rune()
+ }
+ }
+ lStart := len(p.litBs) - 1
+ runeLoop:
+ for {
+ switch r {
+ case utf8.RuneSelf, '\n':
+ break runeLoop
+ case '`':
+ if p.backquoteEnd() {
+ break runeLoop
+ }
+ case escNewl:
+ p.litBs = append(p.litBs, '\\', '\n')
+ break runeLoop
+ }
+ r = p.rune()
+ }
+ if lStart < 0 {
+ continue
+ }
+ // Compare the current line with the stop word.
+ line := p.litBs[lStart:]
+ if r != utf8.RuneSelf && len(line) > 0 {
+ line = line[:len(line)-1] // minus \n
+ }
+ if bytes.Equal(line, stop) {
+ p.hdocStops[len(p.hdocStops)-1] = nil
+ val := p.endLit()[:lStart]
+ if val == "" {
+ return nil
+ }
+ return p.wordOne(p.lit(pos, val))
+ }
+ }
+}
+
+func (p *Parser) advanceLitRe(r rune) {
+ for p.newLit(r); ; r = p.rune() {
+ switch r {
+ case '\\':
+ p.rune()
+ case '(':
+ p.rxOpenParens++
+ case ')':
+ if p.rxOpenParens--; p.rxOpenParens < 0 {
+ p.tok, p.val = _LitWord, p.endLit()
+ p.quote = noState
+ return
+ }
+ case ' ', '\t', '\r', '\n', ';', '&', '>', '<':
+ if p.rxOpenParens <= 0 {
+ p.tok, p.val = _LitWord, p.endLit()
+ p.quote = noState
+ return
+ }
+ case '"', '\'', '$', '`':
+ p.tok, p.val = _Lit, p.endLit()
+ return
+ case utf8.RuneSelf:
+ p.tok, p.val = _LitWord, p.endLit()
+ p.quote = noState
+ return
+ }
+ }
+}
+
+func testUnaryOp(val string) UnTestOperator {
+ switch val {
+ case "!":
+ return TsNot
+ case "-e", "-a":
+ return TsExists
+ case "-f":
+ return TsRegFile
+ case "-d":
+ return TsDirect
+ case "-c":
+ return TsCharSp
+ case "-b":
+ return TsBlckSp
+ case "-p":
+ return TsNmPipe
+ case "-S":
+ return TsSocket
+ case "-L", "-h":
+ return TsSmbLink
+ case "-k":
+ return TsSticky
+ case "-g":
+ return TsGIDSet
+ case "-u":
+ return TsUIDSet
+ case "-G":
+ return TsGrpOwn
+ case "-O":
+ return TsUsrOwn
+ case "-N":
+ return TsModif
+ case "-r":
+ return TsRead
+ case "-w":
+ return TsWrite
+ case "-x":
+ return TsExec
+ case "-s":
+ return TsNoEmpty
+ case "-t":
+ return TsFdTerm
+ case "-z":
+ return TsEmpStr
+ case "-n":
+ return TsNempStr
+ case "-o":
+ return TsOptSet
+ case "-v":
+ return TsVarSet
+ case "-R":
+ return TsRefVar
+ default:
+ return 0
+ }
+}
+
+func testBinaryOp(val string) BinTestOperator {
+ switch val {
+ case "=":
+ return TsMatchShort
+ case "==":
+ return TsMatch
+ case "!=":
+ return TsNoMatch
+ case "=~":
+ return TsReMatch
+ case "-nt":
+ return TsNewer
+ case "-ot":
+ return TsOlder
+ case "-ef":
+ return TsDevIno
+ case "-eq":
+ return TsEql
+ case "-ne":
+ return TsNeq
+ case "-le":
+ return TsLeq
+ case "-ge":
+ return TsGeq
+ case "-lt":
+ return TsLss
+ case "-gt":
+ return TsGtr
+ default:
+ return 0
+ }
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/nodes.go b/vendor/mvdan.cc/sh/v3/syntax/nodes.go
new file mode 100644
index 00000000..a43021f7
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/nodes.go
@@ -0,0 +1,953 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "strconv"
+ "strings"
+)
+
+// Node represents a syntax tree node.
+type Node interface {
+ // Pos returns the position of the first character of the node. Comments
+ // are ignored, except if the node is a *File.
+ Pos() Pos
+ // End returns the position of the character immediately after the node.
+ // If the character is a newline, the line number won't cross into the
+ // next line. Comments are ignored, except if the node is a *File.
+ End() Pos
+}
+
+// File represents a shell source file.
+type File struct {
+ Name string
+
+ Stmts []*Stmt
+ Last []Comment
+}
+
+func (f *File) Pos() Pos { return stmtsPos(f.Stmts, f.Last) }
+func (f *File) End() Pos { return stmtsEnd(f.Stmts, f.Last) }
+
+func stmtsPos(stmts []*Stmt, last []Comment) Pos {
+ if len(stmts) > 0 {
+ s := stmts[0]
+ sPos := s.Pos()
+ if len(s.Comments) > 0 {
+ if cPos := s.Comments[0].Pos(); sPos.After(cPos) {
+ return cPos
+ }
+ }
+ return sPos
+ }
+ if len(last) > 0 {
+ return last[0].Pos()
+ }
+ return Pos{}
+}
+
+func stmtsEnd(stmts []*Stmt, last []Comment) Pos {
+ if len(last) > 0 {
+ return last[len(last)-1].End()
+ }
+ if len(stmts) > 0 {
+ s := stmts[len(stmts)-1]
+ sEnd := s.End()
+ if len(s.Comments) > 0 {
+ if cEnd := s.Comments[0].End(); cEnd.After(sEnd) {
+ return cEnd
+ }
+ }
+ return sEnd
+ }
+ return Pos{}
+}
+
+// Pos is a position within a shell source file.
+type Pos struct {
+ offs, lineCol uint32
+}
+
+// We used to split line and column numbers evenly in 16 bits, but line numbers
+// are significantly more important in practice. Use more bits for them.
+const (
+ lineBitSize = 18
+ lineMax = (1 << lineBitSize) - 1
+
+ colBitSize = 32 - lineBitSize
+ colMax = (1 << colBitSize) - 1
+ colBitMask = colMax
+)
+
+// TODO(v4): consider using uint32 for Offset/Line/Col to better represent bit sizes.
+// Or go with int64, which more closely resembles portable "sizes" elsewhere.
+// The latter is probably nicest, as then we can change the number of internal
+// bits later, and we can also do overflow checks for the user in NewPos.
+
+// NewPos creates a position with the given offset, line, and column.
+//
+// Note that Pos uses a limited number of bits to store these numbers.
+// If line or column overflow their allocated space, they are replaced with 0.
+func NewPos(offset, line, column uint) Pos {
+ if line > lineMax {
+ line = 0 // protect against overflows; rendered as "?"
+ }
+ if column > colMax {
+ column = 0 // protect against overflows; rendered as "?"
+ }
+ return Pos{
+ offs: uint32(offset),
+ lineCol: (uint32(line) << colBitSize) | uint32(column),
+ }
+}
+
+// Offset returns the byte offset of the position in the original source file.
+// Byte offsets start at 0.
+//
+// Note that Offset is not protected against overflows;
+// if an input is larger than 4GiB, the offset will wrap around to 0.
+func (p Pos) Offset() uint { return uint(p.offs) }
+
+// Line returns the line number of the position, starting at 1.
+//
+// Line is protected against overflows; if an input has too many lines, extra
+// lines will have a line number of 0, rendered as "?" by Pos.String.
+func (p Pos) Line() uint { return uint(p.lineCol >> colBitSize) }
+
+// Col returns the column number of the position, starting at 1. It counts in
+// bytes.
+//
+// Col is protected against overflows; if an input line has too many columns,
+// extra columns will have a column number of 0, rendered as "?" by Pos.String.
+func (p Pos) Col() uint { return uint(p.lineCol & colBitMask) }
+
+func (p Pos) String() string {
+ var b strings.Builder
+ if line := p.Line(); line > 0 {
+ b.WriteString(strconv.FormatUint(uint64(line), 10))
+ } else {
+ b.WriteByte('?')
+ }
+ b.WriteByte(':')
+ if col := p.Col(); col > 0 {
+ b.WriteString(strconv.FormatUint(uint64(col), 10))
+ } else {
+ b.WriteByte('?')
+ }
+ return b.String()
+}
+
+// IsValid reports whether the position contains useful position information.
+// Some positions returned via Parse may be invalid: for example, Stmt.Semicolon
+// will only be valid if a statement contained a closing token such as ';'.
+func (p Pos) IsValid() bool { return p != Pos{} }
+
+// After reports whether the position p is after p2. It is a more expressive
+// version of p.Offset() > p2.Offset().
+func (p Pos) After(p2 Pos) bool { return p.offs > p2.offs }
+
+func posAddCol(p Pos, n int) Pos {
+ // TODO: guard against overflows
+ p.lineCol += uint32(n)
+ p.offs += uint32(n)
+ return p
+}
+
+func posMax(p1, p2 Pos) Pos {
+ if p2.After(p1) {
+ return p2
+ }
+ return p1
+}
+
+// Comment represents a single comment on a single line.
+type Comment struct {
+ Hash Pos
+ Text string
+}
+
+func (c *Comment) Pos() Pos { return c.Hash }
+func (c *Comment) End() Pos { return posAddCol(c.Hash, 1+len(c.Text)) }
+
+// Stmt represents a statement, also known as a "complete command". It is
+// compromised of a command and other components that may come before or after
+// it.
+type Stmt struct {
+ Comments []Comment
+ Cmd Command
+ Position Pos
+ Semicolon Pos // position of ';', '&', or '|&', if any
+ Negated bool // ! stmt
+ Background bool // stmt &
+ Coprocess bool // mksh's |&
+
+ Redirs []*Redirect // stmt >a 0 {
+ end = posMax(end, s.Redirs[len(s.Redirs)-1].End())
+ }
+ return end
+}
+
+// Command represents all nodes that are simple or compound commands, including
+// function declarations.
+//
+// These are *CallExpr, *IfClause, *WhileClause, *ForClause, *CaseClause,
+// *Block, *Subshell, *BinaryCmd, *FuncDecl, *ArithmCmd, *TestClause,
+// *DeclClause, *LetClause, *TimeClause, and *CoprocClause.
+type Command interface {
+ Node
+ commandNode()
+}
+
+func (*CallExpr) commandNode() {}
+func (*IfClause) commandNode() {}
+func (*WhileClause) commandNode() {}
+func (*ForClause) commandNode() {}
+func (*CaseClause) commandNode() {}
+func (*Block) commandNode() {}
+func (*Subshell) commandNode() {}
+func (*BinaryCmd) commandNode() {}
+func (*FuncDecl) commandNode() {}
+func (*ArithmCmd) commandNode() {}
+func (*TestClause) commandNode() {}
+func (*DeclClause) commandNode() {}
+func (*LetClause) commandNode() {}
+func (*TimeClause) commandNode() {}
+func (*CoprocClause) commandNode() {}
+func (*TestDecl) commandNode() {}
+
+// Assign represents an assignment to a variable.
+//
+// Here and elsewhere, Index can mean either an index expression into an indexed
+// array, or a string key into an associative array.
+//
+// If Index is non-nil, the value will be a word and not an array as nested
+// arrays are not allowed.
+//
+// If Naked is true and Name is nil, the assignment is part of a DeclClause and
+// the argument (in the Value field) will be evaluated at run-time. This
+// includes parameter expansions, which may expand to assignments or options.
+type Assign struct {
+ Append bool // +=
+ Naked bool // without '='
+ Name *Lit // must be a valid name
+ Index ArithmExpr // [i], ["k"]
+ Value *Word // =val
+ Array *ArrayExpr // =(arr)
+}
+
+func (a *Assign) Pos() Pos {
+ if a.Name == nil {
+ return a.Value.Pos()
+ }
+ return a.Name.Pos()
+}
+
+func (a *Assign) End() Pos {
+ if a.Value != nil {
+ return a.Value.End()
+ }
+ if a.Array != nil {
+ return a.Array.End()
+ }
+ if a.Index != nil {
+ return posAddCol(a.Index.End(), 2)
+ }
+ if a.Naked {
+ return a.Name.End()
+ }
+ return posAddCol(a.Name.End(), 1)
+}
+
+// Redirect represents an input/output redirection.
+type Redirect struct {
+ OpPos Pos
+ Op RedirOperator
+ N *Lit // fd>, or {varname}> in Bash
+ Word *Word // >word
+ Hdoc *Word // here-document body
+}
+
+func (r *Redirect) Pos() Pos {
+ if r.N != nil {
+ return r.N.Pos()
+ }
+ return r.OpPos
+}
+
+func (r *Redirect) End() Pos {
+ if r.Hdoc != nil {
+ return r.Hdoc.End()
+ }
+ return r.Word.End()
+}
+
+// CallExpr represents a command execution or function call, otherwise known as
+// a "simple command".
+//
+// If Args is empty, Assigns apply to the shell environment. Otherwise, they are
+// variables that cannot be arrays and which only apply to the call.
+type CallExpr struct {
+ Assigns []*Assign // a=x b=y args
+ Args []*Word
+}
+
+func (c *CallExpr) Pos() Pos {
+ if len(c.Assigns) > 0 {
+ return c.Assigns[0].Pos()
+ }
+ return c.Args[0].Pos()
+}
+
+func (c *CallExpr) End() Pos {
+ if len(c.Args) == 0 {
+ return c.Assigns[len(c.Assigns)-1].End()
+ }
+ return c.Args[len(c.Args)-1].End()
+}
+
+// Subshell represents a series of commands that should be executed in a nested
+// shell environment.
+type Subshell struct {
+ Lparen, Rparen Pos
+
+ Stmts []*Stmt
+ Last []Comment
+}
+
+func (s *Subshell) Pos() Pos { return s.Lparen }
+func (s *Subshell) End() Pos { return posAddCol(s.Rparen, 1) }
+
+// Block represents a series of commands that should be executed in a nested
+// scope. It is essentially a list of statements within curly braces.
+type Block struct {
+ Lbrace, Rbrace Pos
+
+ Stmts []*Stmt
+ Last []Comment
+}
+
+func (b *Block) Pos() Pos { return b.Lbrace }
+func (b *Block) End() Pos { return posAddCol(b.Rbrace, 1) }
+
+// IfClause represents an if statement.
+type IfClause struct {
+ Position Pos // position of the starting "if", "elif", or "else" token
+ ThenPos Pos // position of "then", empty if this is an "else"
+ FiPos Pos // position of "fi", shared with .Else if non-nil
+
+ Cond []*Stmt
+ CondLast []Comment
+ Then []*Stmt
+ ThenLast []Comment
+
+ Else *IfClause // if non-nil, an "elif" or an "else"
+
+ Last []Comment // comments on the first "elif", "else", or "fi"
+}
+
+func (c *IfClause) Pos() Pos { return c.Position }
+func (c *IfClause) End() Pos { return posAddCol(c.FiPos, 2) }
+
+// WhileClause represents a while or an until clause.
+type WhileClause struct {
+ WhilePos, DoPos, DonePos Pos
+ Until bool
+
+ Cond []*Stmt
+ CondLast []Comment
+ Do []*Stmt
+ DoLast []Comment
+}
+
+func (w *WhileClause) Pos() Pos { return w.WhilePos }
+func (w *WhileClause) End() Pos { return posAddCol(w.DonePos, 4) }
+
+// ForClause represents a for or a select clause. The latter is only present in
+// Bash.
+type ForClause struct {
+ ForPos, DoPos, DonePos Pos
+ Select bool
+ Braces bool // deprecated form with { } instead of do/done
+ Loop Loop
+
+ Do []*Stmt
+ DoLast []Comment
+}
+
+func (f *ForClause) Pos() Pos { return f.ForPos }
+func (f *ForClause) End() Pos { return posAddCol(f.DonePos, 4) }
+
+// Loop holds either *WordIter or *CStyleLoop.
+type Loop interface {
+ Node
+ loopNode()
+}
+
+func (*WordIter) loopNode() {}
+func (*CStyleLoop) loopNode() {}
+
+// WordIter represents the iteration of a variable over a series of words in a
+// for clause. If InPos is an invalid position, the "in" token was missing, so
+// the iteration is over the shell's positional parameters.
+type WordIter struct {
+ Name *Lit
+ InPos Pos // position of "in"
+ Items []*Word
+}
+
+func (w *WordIter) Pos() Pos { return w.Name.Pos() }
+func (w *WordIter) End() Pos {
+ if len(w.Items) > 0 {
+ return wordLastEnd(w.Items)
+ }
+ return posMax(w.Name.End(), posAddCol(w.InPos, 2))
+}
+
+// CStyleLoop represents the behavior of a for clause similar to the C
+// language.
+//
+// This node will only appear with LangBash.
+type CStyleLoop struct {
+ Lparen, Rparen Pos
+ // Init, Cond, Post can each be nil, if the for loop construct omits it.
+ Init, Cond, Post ArithmExpr
+}
+
+func (c *CStyleLoop) Pos() Pos { return c.Lparen }
+func (c *CStyleLoop) End() Pos { return posAddCol(c.Rparen, 2) }
+
+// BinaryCmd represents a binary expression between two statements.
+type BinaryCmd struct {
+ OpPos Pos
+ Op BinCmdOperator
+ X, Y *Stmt
+}
+
+func (b *BinaryCmd) Pos() Pos { return b.X.Pos() }
+func (b *BinaryCmd) End() Pos { return b.Y.End() }
+
+// FuncDecl represents the declaration of a function.
+type FuncDecl struct {
+ Position Pos
+ RsrvWord bool // non-posix "function f" style
+ Parens bool // with () parentheses, only meaningful with RsrvWord=true
+ Name *Lit
+ Body *Stmt
+}
+
+func (f *FuncDecl) Pos() Pos { return f.Position }
+func (f *FuncDecl) End() Pos { return f.Body.End() }
+
+// Word represents a shell word, containing one or more word parts contiguous to
+// each other. The word is delimited by word boundaries, such as spaces,
+// newlines, semicolons, or parentheses.
+type Word struct {
+ Parts []WordPart
+}
+
+func (w *Word) Pos() Pos { return w.Parts[0].Pos() }
+func (w *Word) End() Pos { return w.Parts[len(w.Parts)-1].End() }
+
+// Lit returns the word as a literal value, if the word consists of *Lit nodes
+// only. An empty string is returned otherwise. Words with multiple literals,
+// which can appear in some edge cases, are handled properly.
+//
+// For example, the word "foo" will return "foo", but the word "foo${bar}" will
+// return "".
+func (w *Word) Lit() string {
+ // In the usual case, we'll have either a single part that's a literal,
+ // or one of the parts being a non-literal. Using strings.Join instead
+ // of a strings.Builder avoids extra work in these cases, since a single
+ // part is a shortcut, and many parts don't incur string copies.
+ lits := make([]string, 0, 1)
+ for _, part := range w.Parts {
+ lit, ok := part.(*Lit)
+ if !ok {
+ return ""
+ }
+ lits = append(lits, lit.Value)
+ }
+ return strings.Join(lits, "")
+}
+
+// WordPart represents all nodes that can form part of a word.
+//
+// These are *Lit, *SglQuoted, *DblQuoted, *ParamExp, *CmdSubst, *ArithmExp,
+// *ProcSubst, and *ExtGlob.
+type WordPart interface {
+ Node
+ wordPartNode()
+}
+
+func (*Lit) wordPartNode() {}
+func (*SglQuoted) wordPartNode() {}
+func (*DblQuoted) wordPartNode() {}
+func (*ParamExp) wordPartNode() {}
+func (*CmdSubst) wordPartNode() {}
+func (*ArithmExp) wordPartNode() {}
+func (*ProcSubst) wordPartNode() {}
+func (*ExtGlob) wordPartNode() {}
+func (*BraceExp) wordPartNode() {}
+
+// Lit represents a string literal.
+//
+// Note that a parsed string literal may not appear as-is in the original source
+// code, as it is possible to split literals by escaping newlines. The splitting
+// is lost, but the end position is not.
+type Lit struct {
+ ValuePos, ValueEnd Pos
+ Value string
+}
+
+func (l *Lit) Pos() Pos { return l.ValuePos }
+func (l *Lit) End() Pos { return l.ValueEnd }
+
+// SglQuoted represents a string within single quotes.
+type SglQuoted struct {
+ Left, Right Pos
+ Dollar bool // $''
+ Value string
+}
+
+func (q *SglQuoted) Pos() Pos { return q.Left }
+func (q *SglQuoted) End() Pos { return posAddCol(q.Right, 1) }
+
+// DblQuoted represents a list of nodes within double quotes.
+type DblQuoted struct {
+ Left, Right Pos
+ Dollar bool // $""
+ Parts []WordPart
+}
+
+func (q *DblQuoted) Pos() Pos { return q.Left }
+func (q *DblQuoted) End() Pos { return posAddCol(q.Right, 1) }
+
+// CmdSubst represents a command substitution.
+type CmdSubst struct {
+ Left, Right Pos
+
+ Stmts []*Stmt
+ Last []Comment
+
+ Backquotes bool // deprecated `foo`
+ TempFile bool // mksh's ${ foo;}
+ ReplyVar bool // mksh's ${|foo;}
+}
+
+func (c *CmdSubst) Pos() Pos { return c.Left }
+func (c *CmdSubst) End() Pos { return posAddCol(c.Right, 1) }
+
+// ParamExp represents a parameter expansion.
+type ParamExp struct {
+ Dollar, Rbrace Pos
+
+ Short bool // $a instead of ${a}
+ Excl bool // ${!a}
+ Length bool // ${#a}
+ Width bool // ${%a}
+ Param *Lit
+ Index ArithmExpr // ${a[i]}, ${a["k"]}
+ Slice *Slice // ${a:x:y}
+ Repl *Replace // ${a/x/y}
+ Names ParNamesOperator // ${!prefix*} or ${!prefix@}
+ Exp *Expansion // ${a:-b}, ${a#b}, etc
+}
+
+func (p *ParamExp) Pos() Pos { return p.Dollar }
+func (p *ParamExp) End() Pos {
+ if !p.Short {
+ return posAddCol(p.Rbrace, 1)
+ }
+ if p.Index != nil {
+ return posAddCol(p.Index.End(), 1)
+ }
+ return p.Param.End()
+}
+
+func (p *ParamExp) nakedIndex() bool {
+ return p.Short && p.Index != nil
+}
+
+// Slice represents a character slicing expression inside a ParamExp.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type Slice struct {
+ Offset, Length ArithmExpr
+}
+
+// Replace represents a search and replace expression inside a ParamExp.
+type Replace struct {
+ All bool
+ Orig, With *Word
+}
+
+// Expansion represents string manipulation in a ParamExp other than those
+// covered by Replace.
+type Expansion struct {
+ Op ParExpOperator
+ Word *Word
+}
+
+// ArithmExp represents an arithmetic expansion.
+type ArithmExp struct {
+ Left, Right Pos
+ Bracket bool // deprecated $[expr] form
+ Unsigned bool // mksh's $((# expr))
+
+ X ArithmExpr
+}
+
+func (a *ArithmExp) Pos() Pos { return a.Left }
+func (a *ArithmExp) End() Pos {
+ if a.Bracket {
+ return posAddCol(a.Right, 1)
+ }
+ return posAddCol(a.Right, 2)
+}
+
+// ArithmCmd represents an arithmetic command.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type ArithmCmd struct {
+ Left, Right Pos
+ Unsigned bool // mksh's ((# expr))
+
+ X ArithmExpr
+}
+
+func (a *ArithmCmd) Pos() Pos { return a.Left }
+func (a *ArithmCmd) End() Pos { return posAddCol(a.Right, 2) }
+
+// ArithmExpr represents all nodes that form arithmetic expressions.
+//
+// These are *BinaryArithm, *UnaryArithm, *ParenArithm, and *Word.
+type ArithmExpr interface {
+ Node
+ arithmExprNode()
+}
+
+func (*BinaryArithm) arithmExprNode() {}
+func (*UnaryArithm) arithmExprNode() {}
+func (*ParenArithm) arithmExprNode() {}
+func (*Word) arithmExprNode() {}
+
+// BinaryArithm represents a binary arithmetic expression.
+//
+// If Op is any assign operator, X will be a word with a single *Lit whose value
+// is a valid name.
+//
+// Ternary operators like "a ? b : c" are fit into this structure. Thus, if
+// Op==TernQuest, Y will be a *BinaryArithm with Op==TernColon. Op can only be
+// TernColon in that scenario.
+type BinaryArithm struct {
+ OpPos Pos
+ Op BinAritOperator
+ X, Y ArithmExpr
+}
+
+func (b *BinaryArithm) Pos() Pos { return b.X.Pos() }
+func (b *BinaryArithm) End() Pos { return b.Y.End() }
+
+// UnaryArithm represents an unary arithmetic expression. The unary operator
+// may come before or after the sub-expression.
+//
+// If Op is Inc or Dec, X will be a word with a single *Lit whose value is a
+// valid name.
+type UnaryArithm struct {
+ OpPos Pos
+ Op UnAritOperator
+ Post bool
+ X ArithmExpr
+}
+
+func (u *UnaryArithm) Pos() Pos {
+ if u.Post {
+ return u.X.Pos()
+ }
+ return u.OpPos
+}
+
+func (u *UnaryArithm) End() Pos {
+ if u.Post {
+ return posAddCol(u.OpPos, 2)
+ }
+ return u.X.End()
+}
+
+// ParenArithm represents an arithmetic expression within parentheses.
+type ParenArithm struct {
+ Lparen, Rparen Pos
+
+ X ArithmExpr
+}
+
+func (p *ParenArithm) Pos() Pos { return p.Lparen }
+func (p *ParenArithm) End() Pos { return posAddCol(p.Rparen, 1) }
+
+// CaseClause represents a case (switch) clause.
+type CaseClause struct {
+ Case, In, Esac Pos
+ Braces bool // deprecated mksh form with braces instead of in/esac
+
+ Word *Word
+ Items []*CaseItem
+ Last []Comment
+}
+
+func (c *CaseClause) Pos() Pos { return c.Case }
+func (c *CaseClause) End() Pos { return posAddCol(c.Esac, 4) }
+
+// CaseItem represents a pattern list (case) within a CaseClause.
+type CaseItem struct {
+ Op CaseOperator
+ OpPos Pos // unset if it was finished by "esac"
+ Comments []Comment
+ Patterns []*Word
+
+ Stmts []*Stmt
+ Last []Comment
+}
+
+func (c *CaseItem) Pos() Pos { return c.Patterns[0].Pos() }
+func (c *CaseItem) End() Pos {
+ if c.OpPos.IsValid() {
+ return posAddCol(c.OpPos, len(c.Op.String()))
+ }
+ return stmtsEnd(c.Stmts, c.Last)
+}
+
+// TestClause represents a Bash extended test clause.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type TestClause struct {
+ Left, Right Pos
+
+ X TestExpr
+}
+
+func (t *TestClause) Pos() Pos { return t.Left }
+func (t *TestClause) End() Pos { return posAddCol(t.Right, 2) }
+
+// TestExpr represents all nodes that form test expressions.
+//
+// These are *BinaryTest, *UnaryTest, *ParenTest, and *Word.
+type TestExpr interface {
+ Node
+ testExprNode()
+}
+
+func (*BinaryTest) testExprNode() {}
+func (*UnaryTest) testExprNode() {}
+func (*ParenTest) testExprNode() {}
+func (*Word) testExprNode() {}
+
+// BinaryTest represents a binary test expression.
+type BinaryTest struct {
+ OpPos Pos
+ Op BinTestOperator
+ X, Y TestExpr
+}
+
+func (b *BinaryTest) Pos() Pos { return b.X.Pos() }
+func (b *BinaryTest) End() Pos { return b.Y.End() }
+
+// UnaryTest represents a unary test expression. The unary operator may come
+// before or after the sub-expression.
+type UnaryTest struct {
+ OpPos Pos
+ Op UnTestOperator
+ X TestExpr
+}
+
+func (u *UnaryTest) Pos() Pos { return u.OpPos }
+func (u *UnaryTest) End() Pos { return u.X.End() }
+
+// ParenTest represents a test expression within parentheses.
+type ParenTest struct {
+ Lparen, Rparen Pos
+
+ X TestExpr
+}
+
+func (p *ParenTest) Pos() Pos { return p.Lparen }
+func (p *ParenTest) End() Pos { return posAddCol(p.Rparen, 1) }
+
+// DeclClause represents a Bash declare clause.
+//
+// Args can contain a mix of regular and naked assignments. The naked
+// assignments can represent either options or variable names.
+//
+// This node will only appear with LangBash.
+type DeclClause struct {
+ // Variant is one of "declare", "local", "export", "readonly",
+ // "typeset", or "nameref".
+ Variant *Lit
+ Args []*Assign
+}
+
+func (d *DeclClause) Pos() Pos { return d.Variant.Pos() }
+func (d *DeclClause) End() Pos {
+ if len(d.Args) > 0 {
+ return d.Args[len(d.Args)-1].End()
+ }
+ return d.Variant.End()
+}
+
+// ArrayExpr represents a Bash array expression.
+//
+// This node will only appear with LangBash.
+type ArrayExpr struct {
+ Lparen, Rparen Pos
+
+ Elems []*ArrayElem
+ Last []Comment
+}
+
+func (a *ArrayExpr) Pos() Pos { return a.Lparen }
+func (a *ArrayExpr) End() Pos { return posAddCol(a.Rparen, 1) }
+
+// ArrayElem represents a Bash array element.
+//
+// Index can be nil; for example, declare -a x=(value).
+// Value can be nil; for example, declare -A x=([index]=).
+// Finally, neither can be nil; for example, declare -A x=([index]=value)
+type ArrayElem struct {
+ Index ArithmExpr
+ Value *Word
+ Comments []Comment
+}
+
+func (a *ArrayElem) Pos() Pos {
+ if a.Index != nil {
+ return a.Index.Pos()
+ }
+ return a.Value.Pos()
+}
+
+func (a *ArrayElem) End() Pos {
+ if a.Value != nil {
+ return a.Value.End()
+ }
+ return posAddCol(a.Index.Pos(), 1)
+}
+
+// ExtGlob represents a Bash extended globbing expression. Note that these are
+// parsed independently of whether shopt has been called or not.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type ExtGlob struct {
+ OpPos Pos
+ Op GlobOperator
+ Pattern *Lit
+}
+
+func (e *ExtGlob) Pos() Pos { return e.OpPos }
+func (e *ExtGlob) End() Pos { return posAddCol(e.Pattern.End(), 1) }
+
+// ProcSubst represents a Bash process substitution.
+//
+// This node will only appear with LangBash.
+type ProcSubst struct {
+ OpPos, Rparen Pos
+ Op ProcOperator
+
+ Stmts []*Stmt
+ Last []Comment
+}
+
+func (s *ProcSubst) Pos() Pos { return s.OpPos }
+func (s *ProcSubst) End() Pos { return posAddCol(s.Rparen, 1) }
+
+// TimeClause represents a Bash time clause. PosixFormat corresponds to the -p
+// flag.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type TimeClause struct {
+ Time Pos
+ PosixFormat bool
+ Stmt *Stmt
+}
+
+func (c *TimeClause) Pos() Pos { return c.Time }
+func (c *TimeClause) End() Pos {
+ if c.Stmt == nil {
+ return posAddCol(c.Time, 4)
+ }
+ return c.Stmt.End()
+}
+
+// CoprocClause represents a Bash coproc clause.
+//
+// This node will only appear with LangBash.
+type CoprocClause struct {
+ Coproc Pos
+ Name *Word
+ Stmt *Stmt
+}
+
+func (c *CoprocClause) Pos() Pos { return c.Coproc }
+func (c *CoprocClause) End() Pos { return c.Stmt.End() }
+
+// LetClause represents a Bash let clause.
+//
+// This node will only appear in LangBash and LangMirBSDKorn.
+type LetClause struct {
+ Let Pos
+ Exprs []ArithmExpr
+}
+
+func (l *LetClause) Pos() Pos { return l.Let }
+func (l *LetClause) End() Pos { return l.Exprs[len(l.Exprs)-1].End() }
+
+// BraceExp represents a Bash brace expression, such as "{a,f}" or "{1..10}".
+//
+// This node will only appear as a result of SplitBraces.
+type BraceExp struct {
+ Sequence bool // {x..y[..incr]} instead of {x,y[,...]}
+ Elems []*Word
+}
+
+func (b *BraceExp) Pos() Pos {
+ return posAddCol(b.Elems[0].Pos(), -1)
+}
+
+func (b *BraceExp) End() Pos {
+ return posAddCol(wordLastEnd(b.Elems), 1)
+}
+
+// TestDecl represents the declaration of a Bats test function.
+type TestDecl struct {
+ Position Pos
+ Description *Word
+ Body *Stmt
+}
+
+func (f *TestDecl) Pos() Pos { return f.Position }
+func (f *TestDecl) End() Pos { return f.Body.End() }
+
+func wordLastEnd(ws []*Word) Pos {
+ if len(ws) == 0 {
+ return Pos{}
+ }
+ return ws[len(ws)-1].End()
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/parser.go b/vendor/mvdan.cc/sh/v3/syntax/parser.go
new file mode 100644
index 00000000..86e7274c
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/parser.go
@@ -0,0 +1,2487 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+// ParserOption is a function which can be passed to NewParser
+// to alter its behavior. To apply option to existing Parser
+// call it directly, for example KeepComments(true)(parser).
+type ParserOption func(*Parser)
+
+// KeepComments makes the parser parse comments and attach them to
+// nodes, as opposed to discarding them.
+func KeepComments(enabled bool) ParserOption {
+ return func(p *Parser) { p.keepComments = enabled }
+}
+
+// LangVariant describes a shell language variant to use when tokenizing and
+// parsing shell code. The zero value is LangBash.
+type LangVariant int
+
+const (
+ // LangBash corresponds to the GNU Bash language, as described in its
+ // manual at https://www.gnu.org/software/bash/manual/bash.html.
+ //
+ // We currently follow Bash version 5.1.
+ //
+ // Its string representation is "bash".
+ LangBash LangVariant = iota
+
+ // LangPOSIX corresponds to the POSIX Shell language, as described at
+ // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html.
+ //
+ // Its string representation is "posix" or "sh".
+ LangPOSIX
+
+ // LangMirBSDKorn corresponds to the MirBSD Korn Shell, also known as
+ // mksh, as described at http://www.mirbsd.org/htman/i386/man1/mksh.htm.
+ // Note that it shares some features with Bash, due to the the shared
+ // ancestry that is ksh.
+ //
+ // We currently follow mksh version 59.
+ //
+ // Its string representation is "mksh".
+ LangMirBSDKorn
+
+ // LangBats corresponds to the Bash Automated Testing System language,
+ // as described at https://github.com/bats-core/bats-core. Note that
+ // it's just a small extension of the Bash language.
+ //
+ // Its string representation is "bats".
+ LangBats
+
+ // LangAuto corresponds to automatic language detection,
+ // commonly used by end-user applications like shfmt,
+ // which can guess a file's language variant given its filename or shebang.
+ //
+ // At this time, the Parser does not support LangAuto.
+ LangAuto
+)
+
+// Variant changes the shell language variant that the parser will
+// accept.
+//
+// The passed language variant must be one of the constant values defined in
+// this package.
+func Variant(l LangVariant) ParserOption {
+ switch l {
+ case LangBash, LangPOSIX, LangMirBSDKorn, LangBats:
+ case LangAuto:
+ panic("LangAuto is not supported by the parser at this time")
+ default:
+ panic(fmt.Sprintf("unknown shell language variant: %d", l))
+ }
+ return func(p *Parser) { p.lang = l }
+}
+
+func (l LangVariant) String() string {
+ switch l {
+ case LangBash:
+ return "bash"
+ case LangPOSIX:
+ return "posix"
+ case LangMirBSDKorn:
+ return "mksh"
+ case LangBats:
+ return "bats"
+ case LangAuto:
+ return "auto"
+ }
+ return "unknown shell language variant"
+}
+
+func (l *LangVariant) Set(s string) error {
+ switch s {
+ case "bash":
+ *l = LangBash
+ case "posix", "sh":
+ *l = LangPOSIX
+ case "mksh":
+ *l = LangMirBSDKorn
+ case "bats":
+ *l = LangBats
+ case "auto":
+ *l = LangAuto
+ default:
+ return fmt.Errorf("unknown shell language variant: %q", s)
+ }
+ return nil
+}
+
+func (l LangVariant) isBash() bool {
+ return l == LangBash || l == LangBats
+}
+
+// StopAt configures the lexer to stop at an arbitrary word, treating it
+// as if it were the end of the input. It can contain any characters
+// except whitespace, and cannot be over four bytes in size.
+//
+// This can be useful to embed shell code within another language, as
+// one can use a special word to mark the delimiters between the two.
+//
+// As a word, it will only apply when following whitespace or a
+// separating token. For example, StopAt("$$") will act on the inputs
+// "foo $$" and "foo;$$", but not on "foo '$$'".
+//
+// The match is done by prefix, so the example above will also act on
+// "foo $$bar".
+func StopAt(word string) ParserOption {
+ if len(word) > 4 {
+ panic("stop word can't be over four bytes in size")
+ }
+ if strings.ContainsAny(word, " \t\n\r") {
+ panic("stop word can't contain whitespace characters")
+ }
+ return func(p *Parser) { p.stopAt = []byte(word) }
+}
+
+// NewParser allocates a new Parser and applies any number of options.
+func NewParser(options ...ParserOption) *Parser {
+ p := &Parser{}
+ for _, opt := range options {
+ opt(p)
+ }
+ return p
+}
+
+// Parse reads and parses a shell program with an optional name. It
+// returns the parsed program if no issues were encountered. Otherwise,
+// an error is returned. Reads from r are buffered.
+//
+// Parse can be called more than once, but not concurrently. That is, a
+// Parser can be reused once it is done working.
+func (p *Parser) Parse(r io.Reader, name string) (*File, error) {
+ p.reset()
+ p.f = &File{Name: name}
+ p.src = r
+ p.rune()
+ p.next()
+ p.f.Stmts, p.f.Last = p.stmtList()
+ if p.err == nil {
+ // EOF immediately after heredoc word so no newline to
+ // trigger it
+ p.doHeredocs()
+ }
+ return p.f, p.err
+}
+
+// Stmts reads and parses statements one at a time, calling a function
+// each time one is parsed. If the function returns false, parsing is
+// stopped and the function is not called again.
+func (p *Parser) Stmts(r io.Reader, fn func(*Stmt) bool) error {
+ p.reset()
+ p.f = &File{}
+ p.src = r
+ p.rune()
+ p.next()
+ p.stmts(fn)
+ if p.err == nil {
+ // EOF immediately after heredoc word so no newline to
+ // trigger it
+ p.doHeredocs()
+ }
+ return p.err
+}
+
+type wrappedReader struct {
+ *Parser
+ io.Reader
+
+ lastLine int
+ accumulated []*Stmt
+ fn func([]*Stmt) bool
+}
+
+func (w *wrappedReader) Read(p []byte) (n int, err error) {
+ // If we lexed a newline for the first time, we just finished a line, so
+ // we may need to give a callback for the edge cases below not covered
+ // by Parser.Stmts.
+ if (w.r == '\n' || w.r == escNewl) && w.line > w.lastLine {
+ if w.Incomplete() {
+ // Incomplete statement; call back to print "> ".
+ if !w.fn(w.accumulated) {
+ return 0, io.EOF
+ }
+ } else if len(w.accumulated) == 0 {
+ // Nothing was parsed; call back to print another "$ ".
+ if !w.fn(nil) {
+ return 0, io.EOF
+ }
+ }
+ w.lastLine = w.line
+ }
+ return w.Reader.Read(p)
+}
+
+// Interactive implements what is necessary to parse statements in an
+// interactive shell. The parser will call the given function under two
+// circumstances outlined below.
+//
+// If a line containing any number of statements is parsed, the function will be
+// called with said statements.
+//
+// If a line ending in an incomplete statement is parsed, the function will be
+// called with any fully parsed statements, and Parser.Incomplete will return
+// true.
+//
+// One can imagine a simple interactive shell implementation as follows:
+//
+// fmt.Fprintf(os.Stdout, "$ ")
+// parser.Interactive(os.Stdin, func(stmts []*syntax.Stmt) bool {
+// if parser.Incomplete() {
+// fmt.Fprintf(os.Stdout, "> ")
+// return true
+// }
+// run(stmts)
+// fmt.Fprintf(os.Stdout, "$ ")
+// return true
+// }
+//
+// If the callback function returns false, parsing is stopped and the function
+// is not called again.
+func (p *Parser) Interactive(r io.Reader, fn func([]*Stmt) bool) error {
+ w := wrappedReader{Parser: p, Reader: r, fn: fn}
+ return p.Stmts(&w, func(stmt *Stmt) bool {
+ w.accumulated = append(w.accumulated, stmt)
+ // We finished parsing a statement and we're at a newline token,
+ // so we finished fully parsing a number of statements. Call
+ // back to run the statements and print "$ ".
+ if p.tok == _Newl {
+ if !fn(w.accumulated) {
+ return false
+ }
+ w.accumulated = w.accumulated[:0]
+ // The callback above would already print "$ ", so we
+ // don't want the subsequent wrappedReader.Read to cause
+ // another "$ " print thinking that nothing was parsed.
+ w.lastLine = w.line + 1
+ }
+ return true
+ })
+}
+
+// Words reads and parses words one at a time, calling a function each time one
+// is parsed. If the function returns false, parsing is stopped and the function
+// is not called again.
+//
+// Newlines are skipped, meaning that multi-line input will work fine. If the
+// parser encounters a token that isn't a word, such as a semicolon, an error
+// will be returned.
+//
+// Note that the lexer doesn't currently tokenize spaces, so it may need to read
+// a non-space byte such as a newline or a letter before finishing the parsing
+// of a word. This will be fixed in the future.
+func (p *Parser) Words(r io.Reader, fn func(*Word) bool) error {
+ p.reset()
+ p.f = &File{}
+ p.src = r
+ p.rune()
+ p.next()
+ for {
+ p.got(_Newl)
+ w := p.getWord()
+ if w == nil {
+ if p.tok != _EOF {
+ p.curErr("%s is not a valid word", p.tok)
+ }
+ return p.err
+ }
+ if !fn(w) {
+ return nil
+ }
+ }
+}
+
+// Document parses a single here-document word. That is, it parses the input as
+// if they were lines following a < 0 || p.litBs != nil
+}
+
+const bufSize = 1 << 10
+
+func (p *Parser) reset() {
+ p.tok, p.val = illegalTok, ""
+ p.eqlOffs = 0
+ p.bs, p.bsp = nil, 0
+ p.offs, p.line, p.col = 0, 1, 1
+ p.r, p.w = 0, 0
+ p.err, p.readErr = nil, nil
+ p.quote, p.forbidNested = noState, false
+ p.openStmts = 0
+ p.heredocs, p.buriedHdocs = p.heredocs[:0], 0
+ p.parsingDoc = false
+ p.openBquotes, p.buriedBquotes = 0, 0
+ p.accComs, p.curComs = nil, &p.accComs
+ p.litBatch = nil
+ p.wordBatch = nil
+ p.stmtBatch = nil
+ p.callBatch = nil
+}
+
+func (p *Parser) nextPos() Pos {
+ // TODO: detect offset overflow while lexing as well.
+ var line, col uint
+ if !p.lineOverflow {
+ line = uint(p.line)
+ }
+ if !p.colOverflow {
+ col = uint(p.col)
+ }
+ return NewPos(uint(p.offs+p.bsp-p.w), line, col)
+}
+
+func (p *Parser) lit(pos Pos, val string) *Lit {
+ if len(p.litBatch) == 0 {
+ p.litBatch = make([]Lit, 64)
+ }
+ l := &p.litBatch[0]
+ p.litBatch = p.litBatch[1:]
+ l.ValuePos = pos
+ l.ValueEnd = p.nextPos()
+ l.Value = val
+ return l
+}
+
+type wordAlloc struct {
+ word Word
+ parts [1]WordPart
+}
+
+func (p *Parser) wordAnyNumber() *Word {
+ if len(p.wordBatch) == 0 {
+ p.wordBatch = make([]wordAlloc, 32)
+ }
+ alloc := &p.wordBatch[0]
+ p.wordBatch = p.wordBatch[1:]
+ w := &alloc.word
+ w.Parts = p.wordParts(alloc.parts[:0])
+ return w
+}
+
+func (p *Parser) wordOne(part WordPart) *Word {
+ if len(p.wordBatch) == 0 {
+ p.wordBatch = make([]wordAlloc, 32)
+ }
+ alloc := &p.wordBatch[0]
+ p.wordBatch = p.wordBatch[1:]
+ w := &alloc.word
+ w.Parts = alloc.parts[:1]
+ w.Parts[0] = part
+ return w
+}
+
+func (p *Parser) stmt(pos Pos) *Stmt {
+ if len(p.stmtBatch) == 0 {
+ p.stmtBatch = make([]Stmt, 32)
+ }
+ s := &p.stmtBatch[0]
+ p.stmtBatch = p.stmtBatch[1:]
+ s.Position = pos
+ return s
+}
+
+type callAlloc struct {
+ ce CallExpr
+ ws [4]*Word
+}
+
+func (p *Parser) call(w *Word) *CallExpr {
+ if len(p.callBatch) == 0 {
+ p.callBatch = make([]callAlloc, 32)
+ }
+ alloc := &p.callBatch[0]
+ p.callBatch = p.callBatch[1:]
+ ce := &alloc.ce
+ ce.Args = alloc.ws[:1]
+ ce.Args[0] = w
+ return ce
+}
+
+//go:generate stringer -type=quoteState
+
+type quoteState uint32
+
+const (
+ noState quoteState = 1 << iota
+ subCmd
+ subCmdBckquo
+ dblQuotes
+ hdocWord
+ hdocBody
+ hdocBodyTabs
+ arithmExpr
+ arithmExprLet
+ arithmExprCmd
+ arithmExprBrack
+ testExpr
+ testExprRegexp
+ switchCase
+ paramExpName
+ paramExpSlice
+ paramExpRepl
+ paramExpExp
+ arrayElems
+
+ allKeepSpaces = paramExpRepl | dblQuotes | hdocBody |
+ hdocBodyTabs | paramExpExp
+ allRegTokens = noState | subCmd | subCmdBckquo | hdocWord |
+ switchCase | arrayElems | testExpr
+ allArithmExpr = arithmExpr | arithmExprLet | arithmExprCmd |
+ arithmExprBrack | paramExpSlice
+ allParamReg = paramExpName | paramExpSlice
+ allParamExp = allParamReg | paramExpRepl | paramExpExp | arithmExprBrack
+)
+
+type saveState struct {
+ quote quoteState
+ buriedHdocs int
+}
+
+func (p *Parser) preNested(quote quoteState) (s saveState) {
+ s.quote, s.buriedHdocs = p.quote, p.buriedHdocs
+ p.buriedHdocs, p.quote = len(p.heredocs), quote
+ return
+}
+
+func (p *Parser) postNested(s saveState) {
+ p.quote, p.buriedHdocs = s.quote, s.buriedHdocs
+}
+
+func (p *Parser) unquotedWordBytes(w *Word) ([]byte, bool) {
+ buf := make([]byte, 0, 4)
+ didUnquote := false
+ for _, wp := range w.Parts {
+ buf, didUnquote = p.unquotedWordPart(buf, wp, false)
+ }
+ return buf, didUnquote
+}
+
+func (p *Parser) unquotedWordPart(buf []byte, wp WordPart, quotes bool) (_ []byte, quoted bool) {
+ switch x := wp.(type) {
+ case *Lit:
+ for i := 0; i < len(x.Value); i++ {
+ if b := x.Value[i]; b == '\\' && !quotes {
+ if i++; i < len(x.Value) {
+ buf = append(buf, x.Value[i])
+ }
+ quoted = true
+ } else {
+ buf = append(buf, b)
+ }
+ }
+ case *SglQuoted:
+ buf = append(buf, []byte(x.Value)...)
+ quoted = true
+ case *DblQuoted:
+ for _, wp2 := range x.Parts {
+ buf, _ = p.unquotedWordPart(buf, wp2, true)
+ }
+ quoted = true
+ }
+ return buf, quoted
+}
+
+func (p *Parser) doHeredocs() {
+ hdocs := p.heredocs[p.buriedHdocs:]
+ if len(hdocs) == 0 {
+ // Nothing do do; don't even issue a read.
+ return
+ }
+ p.rune() // consume '\n', since we know p.tok == _Newl
+ old := p.quote
+ p.heredocs = p.heredocs[:p.buriedHdocs]
+ for i, r := range hdocs {
+ if p.err != nil {
+ break
+ }
+ p.quote = hdocBody
+ if r.Op == DashHdoc {
+ p.quote = hdocBodyTabs
+ }
+ stop, quoted := p.unquotedWordBytes(r.Word)
+ p.hdocStops = append(p.hdocStops, stop)
+ if i > 0 && p.r == '\n' {
+ p.rune()
+ }
+ lastLine := p.line
+ if quoted {
+ r.Hdoc = p.quotedHdocWord()
+ } else {
+ p.next()
+ r.Hdoc = p.getWord()
+ }
+ if r.Hdoc != nil {
+ lastLine = int(r.Hdoc.End().Line())
+ }
+ if lastLine < p.line {
+ // TODO: It seems like this triggers more often than it
+ // should. Look into it.
+ l := p.lit(p.nextPos(), "")
+ if r.Hdoc == nil {
+ r.Hdoc = p.wordOne(l)
+ } else {
+ r.Hdoc.Parts = append(r.Hdoc.Parts, l)
+ }
+ }
+ if stop := p.hdocStops[len(p.hdocStops)-1]; stop != nil {
+ p.posErr(r.Pos(), "unclosed here-document '%s'", stop)
+ }
+ p.hdocStops = p.hdocStops[:len(p.hdocStops)-1]
+ }
+ p.quote = old
+}
+
+func (p *Parser) got(tok token) bool {
+ if p.tok == tok {
+ p.next()
+ return true
+ }
+ return false
+}
+
+func (p *Parser) gotRsrv(val string) (Pos, bool) {
+ pos := p.pos
+ if p.tok == _LitWord && p.val == val {
+ p.next()
+ return pos, true
+ }
+ return pos, false
+}
+
+func readableStr(s string) string {
+ // don't quote tokens like & or }
+ if s != "" && s[0] >= 'a' && s[0] <= 'z' {
+ return strconv.Quote(s)
+ }
+ return s
+}
+
+func (p *Parser) followErr(pos Pos, left, right string) {
+ leftStr := readableStr(left)
+ p.posErr(pos, "%s must be followed by %s", leftStr, right)
+}
+
+func (p *Parser) followErrExp(pos Pos, left string) {
+ p.followErr(pos, left, "an expression")
+}
+
+func (p *Parser) follow(lpos Pos, left string, tok token) {
+ if !p.got(tok) {
+ p.followErr(lpos, left, tok.String())
+ }
+}
+
+func (p *Parser) followRsrv(lpos Pos, left, val string) Pos {
+ pos, ok := p.gotRsrv(val)
+ if !ok {
+ p.followErr(lpos, left, fmt.Sprintf("%q", val))
+ }
+ return pos
+}
+
+func (p *Parser) followStmts(left string, lpos Pos, stops ...string) ([]*Stmt, []Comment) {
+ if p.got(semicolon) {
+ return nil, nil
+ }
+ newLine := p.got(_Newl)
+ stmts, last := p.stmtList(stops...)
+ if len(stmts) < 1 && !newLine {
+ p.followErr(lpos, left, "a statement list")
+ }
+ return stmts, last
+}
+
+func (p *Parser) followWordTok(tok token, pos Pos) *Word {
+ w := p.getWord()
+ if w == nil {
+ p.followErr(pos, tok.String(), "a word")
+ }
+ return w
+}
+
+func (p *Parser) stmtEnd(n Node, start, end string) Pos {
+ pos, ok := p.gotRsrv(end)
+ if !ok {
+ p.posErr(n.Pos(), "%s statement must end with %q", start, end)
+ }
+ return pos
+}
+
+func (p *Parser) quoteErr(lpos Pos, quote token) {
+ p.posErr(lpos, "reached %s without closing quote %s",
+ p.tok.String(), quote)
+}
+
+func (p *Parser) matchingErr(lpos Pos, left, right interface{}) {
+ p.posErr(lpos, "reached %s without matching %s with %s",
+ p.tok.String(), left, right)
+}
+
+func (p *Parser) matched(lpos Pos, left, right token) Pos {
+ pos := p.pos
+ if !p.got(right) {
+ p.matchingErr(lpos, left, right)
+ }
+ return pos
+}
+
+func (p *Parser) errPass(err error) {
+ if p.err == nil {
+ p.err = err
+ p.bsp = len(p.bs) + 1
+ p.r = utf8.RuneSelf
+ p.w = 1
+ p.tok = _EOF
+ }
+}
+
+// IsIncomplete reports whether a Parser error could have been avoided with
+// extra input bytes. For example, if an io.EOF was encountered while there was
+// an unclosed quote or parenthesis.
+func IsIncomplete(err error) bool {
+ perr, ok := err.(ParseError)
+ return ok && perr.Incomplete
+}
+
+// IsKeyword returns true if the given word is part of the language keywords.
+func IsKeyword(word string) bool {
+ // This list has been copied from the bash 5.1 source code, file y.tab.c +4460
+ switch word {
+ case
+ "!",
+ "[[", // only if COND_COMMAND is defined
+ "]]", // only if COND_COMMAND is defined
+ "case",
+ "coproc", // only if COPROCESS_SUPPORT is defined
+ "do",
+ "done",
+ "else",
+ "esac",
+ "fi",
+ "for",
+ "function",
+ "if",
+ "in",
+ "select", // only if SELECT_COMMAND is defined
+ "then",
+ "time", // only if COMMAND_TIMING is defined
+ "until",
+ "while",
+ "{",
+ "}":
+ return true
+ }
+ return false
+}
+
+// ParseError represents an error found when parsing a source file, from which
+// the parser cannot recover.
+type ParseError struct {
+ Filename string
+ Pos
+ Text string
+
+ Incomplete bool
+}
+
+func (e ParseError) Error() string {
+ if e.Filename == "" {
+ return fmt.Sprintf("%s: %s", e.Pos.String(), e.Text)
+ }
+ return fmt.Sprintf("%s:%s: %s", e.Filename, e.Pos.String(), e.Text)
+}
+
+// LangError is returned when the parser encounters code that is only valid in
+// other shell language variants. The error includes what feature is not present
+// in the current language variant, and what languages support it.
+type LangError struct {
+ Filename string
+ Pos
+ Feature string
+ Langs []LangVariant
+}
+
+func (e LangError) Error() string {
+ var buf bytes.Buffer
+ if e.Filename != "" {
+ buf.WriteString(e.Filename + ":")
+ }
+ buf.WriteString(e.Pos.String() + ": ")
+ buf.WriteString(e.Feature)
+ if strings.HasSuffix(e.Feature, "s") {
+ buf.WriteString(" are a ")
+ } else {
+ buf.WriteString(" is a ")
+ }
+ for i, lang := range e.Langs {
+ if i > 0 {
+ buf.WriteString("/")
+ }
+ buf.WriteString(lang.String())
+ }
+ buf.WriteString(" feature")
+ return buf.String()
+}
+
+func (p *Parser) posErr(pos Pos, format string, a ...interface{}) {
+ p.errPass(ParseError{
+ Filename: p.f.Name,
+ Pos: pos,
+ Text: fmt.Sprintf(format, a...),
+ Incomplete: p.tok == _EOF && p.Incomplete(),
+ })
+}
+
+func (p *Parser) curErr(format string, a ...interface{}) {
+ p.posErr(p.pos, format, a...)
+}
+
+func (p *Parser) langErr(pos Pos, feature string, langs ...LangVariant) {
+ p.errPass(LangError{
+ Filename: p.f.Name,
+ Pos: pos,
+ Feature: feature,
+ Langs: langs,
+ })
+}
+
+func (p *Parser) stmts(fn func(*Stmt) bool, stops ...string) {
+ gotEnd := true
+loop:
+ for p.tok != _EOF {
+ newLine := p.got(_Newl)
+ switch p.tok {
+ case _LitWord:
+ for _, stop := range stops {
+ if p.val == stop {
+ break loop
+ }
+ }
+ case rightParen:
+ if p.quote == subCmd {
+ break loop
+ }
+ case bckQuote:
+ if p.backquoteEnd() {
+ break loop
+ }
+ case dblSemicolon, semiAnd, dblSemiAnd, semiOr:
+ if p.quote == switchCase {
+ break loop
+ }
+ p.curErr("%s can only be used in a case clause", p.tok)
+ }
+ if !newLine && !gotEnd {
+ p.curErr("statements must be separated by &, ; or a newline")
+ }
+ if p.tok == _EOF {
+ break
+ }
+ p.openStmts++
+ s := p.getStmt(true, false, false)
+ p.openStmts--
+ if s == nil {
+ p.invalidStmtStart()
+ break
+ }
+ gotEnd = s.Semicolon.IsValid()
+ if !fn(s) {
+ break
+ }
+ }
+}
+
+func (p *Parser) stmtList(stops ...string) ([]*Stmt, []Comment) {
+ var stmts []*Stmt
+ var last []Comment
+ fn := func(s *Stmt) bool {
+ stmts = append(stmts, s)
+ return true
+ }
+ p.stmts(fn, stops...)
+ split := len(p.accComs)
+ if p.tok == _LitWord && (p.val == "elif" || p.val == "else" || p.val == "fi") {
+ // Split the comments, so that any aligned with an opening token
+ // get attached to it. For example:
+ //
+ // if foo; then
+ // # inside the body
+ // # document the else
+ // else
+ // fi
+ // TODO(mvdan): look into deduplicating this with similar logic
+ // in caseItems.
+ for i := len(p.accComs) - 1; i >= 0; i-- {
+ c := p.accComs[i]
+ if c.Pos().Col() != p.pos.Col() {
+ break
+ }
+ split = i
+ }
+ }
+ if split > 0 { // keep last nil if empty
+ last = p.accComs[:split]
+ }
+ p.accComs = p.accComs[split:]
+ return stmts, last
+}
+
+func (p *Parser) invalidStmtStart() {
+ switch p.tok {
+ case semicolon, and, or, andAnd, orOr:
+ p.curErr("%s can only immediately follow a statement", p.tok)
+ case rightParen:
+ p.curErr("%s can only be used to close a subshell", p.tok)
+ default:
+ p.curErr("%s is not a valid start for a statement", p.tok)
+ }
+}
+
+func (p *Parser) getWord() *Word {
+ if w := p.wordAnyNumber(); len(w.Parts) > 0 && p.err == nil {
+ return w
+ }
+ return nil
+}
+
+func (p *Parser) getLit() *Lit {
+ switch p.tok {
+ case _Lit, _LitWord, _LitRedir:
+ l := p.lit(p.pos, p.val)
+ p.next()
+ return l
+ }
+ return nil
+}
+
+func (p *Parser) wordParts(wps []WordPart) []WordPart {
+ for {
+ n := p.wordPart()
+ if n == nil {
+ if len(wps) == 0 {
+ return nil // normalize empty lists into nil
+ }
+ return wps
+ }
+ wps = append(wps, n)
+ if p.spaced {
+ return wps
+ }
+ }
+}
+
+func (p *Parser) ensureNoNested() {
+ if p.forbidNested {
+ p.curErr("expansions not allowed in heredoc words")
+ }
+}
+
+func (p *Parser) wordPart() WordPart {
+ switch p.tok {
+ case _Lit, _LitWord, _LitRedir:
+ l := p.lit(p.pos, p.val)
+ p.next()
+ return l
+ case dollBrace:
+ p.ensureNoNested()
+ switch p.r {
+ case '|':
+ if p.lang != LangMirBSDKorn {
+ p.curErr(`"${|stmts;}" is a mksh feature`)
+ }
+ fallthrough
+ case ' ', '\t', '\n':
+ if p.lang != LangMirBSDKorn {
+ p.curErr(`"${ stmts;}" is a mksh feature`)
+ }
+ cs := &CmdSubst{
+ Left: p.pos,
+ TempFile: p.r != '|',
+ ReplyVar: p.r == '|',
+ }
+ old := p.preNested(subCmd)
+ p.rune() // don't tokenize '|'
+ p.next()
+ cs.Stmts, cs.Last = p.stmtList("}")
+ p.postNested(old)
+ pos, ok := p.gotRsrv("}")
+ if !ok {
+ p.matchingErr(cs.Left, "${", "}")
+ }
+ cs.Right = pos
+ return cs
+ default:
+ return p.paramExp()
+ }
+ case dollDblParen, dollBrack:
+ p.ensureNoNested()
+ left := p.tok
+ ar := &ArithmExp{Left: p.pos, Bracket: left == dollBrack}
+ var old saveState
+ if ar.Bracket {
+ old = p.preNested(arithmExprBrack)
+ } else {
+ old = p.preNested(arithmExpr)
+ }
+ p.next()
+ if p.got(hash) {
+ if p.lang != LangMirBSDKorn {
+ p.langErr(ar.Pos(), "unsigned expressions", LangMirBSDKorn)
+ }
+ ar.Unsigned = true
+ }
+ ar.X = p.followArithm(left, ar.Left)
+ if ar.Bracket {
+ if p.tok != rightBrack {
+ p.arithmMatchingErr(ar.Left, dollBrack, rightBrack)
+ }
+ p.postNested(old)
+ ar.Right = p.pos
+ p.next()
+ } else {
+ ar.Right = p.arithmEnd(dollDblParen, ar.Left, old)
+ }
+ return ar
+ case dollParen:
+ p.ensureNoNested()
+ cs := &CmdSubst{Left: p.pos}
+ old := p.preNested(subCmd)
+ p.next()
+ cs.Stmts, cs.Last = p.stmtList()
+ p.postNested(old)
+ cs.Right = p.matched(cs.Left, leftParen, rightParen)
+ return cs
+ case dollar:
+ r := p.r
+ switch {
+ case singleRuneParam(r):
+ p.tok, p.val = _LitWord, string(r)
+ p.rune()
+ case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z',
+ '0' <= r && r <= '9', r == '_', r == '\\':
+ p.advanceNameCont(r)
+ default:
+ l := p.lit(p.pos, "$")
+ p.next()
+ return l
+ }
+ p.ensureNoNested()
+ pe := &ParamExp{Dollar: p.pos, Short: true}
+ p.pos = posAddCol(p.pos, 1)
+ pe.Param = p.getLit()
+ if pe.Param != nil && pe.Param.Value == "" {
+ l := p.lit(pe.Dollar, "$")
+ // e.g. "$\\\"" within double quotes, so we must
+ // keep the rest of the literal characters.
+ l.ValueEnd = posAddCol(l.ValuePos, 1)
+ return l
+ }
+ return pe
+ case cmdIn, cmdOut:
+ p.ensureNoNested()
+ ps := &ProcSubst{Op: ProcOperator(p.tok), OpPos: p.pos}
+ old := p.preNested(subCmd)
+ p.next()
+ ps.Stmts, ps.Last = p.stmtList()
+ p.postNested(old)
+ ps.Rparen = p.matched(ps.OpPos, token(ps.Op), rightParen)
+ return ps
+ case sglQuote, dollSglQuote:
+ sq := &SglQuoted{Left: p.pos, Dollar: p.tok == dollSglQuote}
+ r := p.r
+ for p.newLit(r); ; r = p.rune() {
+ switch r {
+ case '\\':
+ if sq.Dollar {
+ p.rune()
+ }
+ case '\'':
+ sq.Right = p.nextPos()
+ sq.Value = p.endLit()
+
+ // restore openBquotes
+ p.openBquotes = p.buriedBquotes
+ p.buriedBquotes = 0
+
+ p.rune()
+ p.next()
+ return sq
+ case escNewl:
+ p.litBs = append(p.litBs, '\\', '\n')
+ case utf8.RuneSelf:
+ p.tok = _EOF
+ p.quoteErr(sq.Pos(), sglQuote)
+ return nil
+ }
+ }
+ case dblQuote, dollDblQuote:
+ if p.quote == dblQuotes {
+ // p.tok == dblQuote, as "foo$" puts $ in the lit
+ return nil
+ }
+ return p.dblQuoted()
+ case bckQuote:
+ if p.backquoteEnd() {
+ return nil
+ }
+ p.ensureNoNested()
+ cs := &CmdSubst{Left: p.pos, Backquotes: true}
+ old := p.preNested(subCmdBckquo)
+ p.openBquotes++
+
+ // The lexer didn't call p.rune for us, so that it could have
+ // the right p.openBquotes to properly handle backslashes.
+ p.rune()
+
+ p.next()
+ cs.Stmts, cs.Last = p.stmtList()
+ if p.tok == bckQuote && p.lastBquoteEsc < p.openBquotes-1 {
+ // e.g. found ` before the nested backquote \` was closed.
+ p.tok = _EOF
+ p.quoteErr(cs.Pos(), bckQuote)
+ }
+ p.postNested(old)
+ p.openBquotes--
+ cs.Right = p.pos
+
+ // Like above, the lexer didn't call p.rune for us.
+ p.rune()
+ if !p.got(bckQuote) {
+ p.quoteErr(cs.Pos(), bckQuote)
+ }
+ return cs
+ case globQuest, globStar, globPlus, globAt, globExcl:
+ if p.lang == LangPOSIX {
+ p.langErr(p.pos, "extended globs", LangBash, LangMirBSDKorn)
+ }
+ eg := &ExtGlob{Op: GlobOperator(p.tok), OpPos: p.pos}
+ lparens := 1
+ r := p.r
+ globLoop:
+ for p.newLit(r); ; r = p.rune() {
+ switch r {
+ case utf8.RuneSelf:
+ break globLoop
+ case '(':
+ lparens++
+ case ')':
+ if lparens--; lparens == 0 {
+ break globLoop
+ }
+ }
+ }
+ eg.Pattern = p.lit(posAddCol(eg.OpPos, 2), p.endLit())
+ p.rune()
+ p.next()
+ if lparens != 0 {
+ p.matchingErr(eg.OpPos, eg.Op, rightParen)
+ }
+ return eg
+ default:
+ return nil
+ }
+}
+
+func (p *Parser) dblQuoted() *DblQuoted {
+ alloc := &struct {
+ quoted DblQuoted
+ parts [1]WordPart
+ }{
+ quoted: DblQuoted{Left: p.pos, Dollar: p.tok == dollDblQuote},
+ }
+ q := &alloc.quoted
+ old := p.quote
+ p.quote = dblQuotes
+ p.next()
+ q.Parts = p.wordParts(alloc.parts[:0])
+ p.quote = old
+ q.Right = p.pos
+ if !p.got(dblQuote) {
+ p.quoteErr(q.Pos(), dblQuote)
+ }
+ return q
+}
+
+func singleRuneParam(r rune) bool {
+ switch r {
+ case '@', '*', '#', '$', '?', '!', '-',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return true
+ }
+ return false
+}
+
+func (p *Parser) paramExp() *ParamExp {
+ pe := &ParamExp{Dollar: p.pos}
+ old := p.quote
+ p.quote = paramExpName
+ if p.r == '#' {
+ p.tok = hash
+ p.pos = p.nextPos()
+ p.rune()
+ } else {
+ p.next()
+ }
+ switch p.tok {
+ case hash:
+ if paramNameOp(p.r) {
+ pe.Length = true
+ p.next()
+ }
+ case perc:
+ if p.lang != LangMirBSDKorn {
+ p.posErr(pe.Pos(), `"${%%foo}" is a mksh feature`)
+ }
+ if paramNameOp(p.r) {
+ pe.Width = true
+ p.next()
+ }
+ case exclMark:
+ if paramNameOp(p.r) {
+ pe.Excl = true
+ p.next()
+ }
+ }
+ op := p.tok
+ switch p.tok {
+ case _Lit, _LitWord:
+ if !numberLiteral(p.val) && !ValidName(p.val) {
+ p.curErr("invalid parameter name")
+ }
+ pe.Param = p.lit(p.pos, p.val)
+ p.next()
+ case quest, minus:
+ if pe.Length && p.r != '}' {
+ // actually ${#-default}, not ${#-}; fix the ambiguity
+ pe.Length = false
+ pe.Param = p.lit(posAddCol(p.pos, -1), "#")
+ pe.Param.ValueEnd = p.pos
+ break
+ }
+ fallthrough
+ case at, star, hash, exclMark, dollar:
+ pe.Param = p.lit(p.pos, p.tok.String())
+ p.next()
+ default:
+ p.curErr("parameter expansion requires a literal")
+ }
+ switch p.tok {
+ case _Lit, _LitWord:
+ p.curErr("%s cannot be followed by a word", op)
+ case rightBrace:
+ if pe.Excl && p.lang == LangPOSIX {
+ p.posErr(pe.Pos(), `"${!foo}" is a bash/mksh feature`)
+ }
+ pe.Rbrace = p.pos
+ p.quote = old
+ p.next()
+ return pe
+ case leftBrack:
+ if p.lang == LangPOSIX {
+ p.langErr(p.pos, "arrays", LangBash, LangMirBSDKorn)
+ }
+ if !ValidName(pe.Param.Value) {
+ p.curErr("cannot index a special parameter name")
+ }
+ pe.Index = p.eitherIndex()
+ }
+ if p.tok == rightBrace {
+ pe.Rbrace = p.pos
+ p.quote = old
+ p.next()
+ return pe
+ }
+ if p.tok != _EOF && (pe.Length || pe.Width) {
+ p.curErr("cannot combine multiple parameter expansion operators")
+ }
+ switch p.tok {
+ case slash, dblSlash:
+ // pattern search and replace
+ if p.lang == LangPOSIX {
+ p.langErr(p.pos, "search and replace", LangBash, LangMirBSDKorn)
+ }
+ pe.Repl = &Replace{All: p.tok == dblSlash}
+ p.quote = paramExpRepl
+ p.next()
+ pe.Repl.Orig = p.getWord()
+ p.quote = paramExpExp
+ if p.got(slash) {
+ pe.Repl.With = p.getWord()
+ }
+ case colon:
+ // slicing
+ if p.lang == LangPOSIX {
+ p.langErr(p.pos, "slicing", LangBash, LangMirBSDKorn)
+ }
+ pe.Slice = &Slice{}
+ colonPos := p.pos
+ p.quote = paramExpSlice
+ if p.next(); p.tok != colon {
+ pe.Slice.Offset = p.followArithm(colon, colonPos)
+ }
+ colonPos = p.pos
+ if p.got(colon) {
+ pe.Slice.Length = p.followArithm(colon, colonPos)
+ }
+ // Need to use a different matched style so arithm errors
+ // get reported correctly
+ p.quote = old
+ pe.Rbrace = p.pos
+ p.matchedArithm(pe.Dollar, dollBrace, rightBrace)
+ return pe
+ case caret, dblCaret, comma, dblComma:
+ // upper/lower case
+ if !p.lang.isBash() {
+ p.langErr(p.pos, "this expansion operator", LangBash)
+ }
+ pe.Exp = p.paramExpExp()
+ case at, star:
+ switch {
+ case p.tok == at && p.lang == LangPOSIX:
+ p.langErr(p.pos, "this expansion operator", LangBash, LangMirBSDKorn)
+ case p.tok == star && !pe.Excl:
+ p.curErr("not a valid parameter expansion operator: %v", p.tok)
+ case pe.Excl && p.r == '}':
+ if !p.lang.isBash() {
+ p.posErr(pe.Pos(), `"${!foo`+p.tok.String()+`}" is a bash feature`)
+ }
+ pe.Names = ParNamesOperator(p.tok)
+ p.next()
+ default:
+ pe.Exp = p.paramExpExp()
+ }
+ case plus, colPlus, minus, colMinus, quest, colQuest, assgn, colAssgn,
+ perc, dblPerc, hash, dblHash:
+ pe.Exp = p.paramExpExp()
+ case _EOF:
+ default:
+ p.curErr("not a valid parameter expansion operator: %v", p.tok)
+ }
+ p.quote = old
+ pe.Rbrace = p.pos
+ p.matched(pe.Dollar, dollBrace, rightBrace)
+ return pe
+}
+
+func (p *Parser) paramExpExp() *Expansion {
+ op := ParExpOperator(p.tok)
+ p.quote = paramExpExp
+ p.next()
+ if op == OtherParamOps {
+ switch p.tok {
+ case _Lit, _LitWord:
+ default:
+ p.curErr("@ expansion operator requires a literal")
+ }
+ switch p.val {
+ case "a", "u", "A", "E", "K", "L", "P", "U":
+ if !p.lang.isBash() {
+ p.langErr(p.pos, "this expansion operator", LangBash)
+ }
+ case "#":
+ if p.lang != LangMirBSDKorn {
+ p.langErr(p.pos, "this expansion operator", LangMirBSDKorn)
+ }
+ case "Q":
+ default:
+ p.curErr("invalid @ expansion operator")
+ }
+ }
+ return &Expansion{Op: op, Word: p.getWord()}
+}
+
+func (p *Parser) eitherIndex() ArithmExpr {
+ old := p.quote
+ lpos := p.pos
+ p.quote = arithmExprBrack
+ p.next()
+ if p.tok == star || p.tok == at {
+ p.tok, p.val = _LitWord, p.tok.String()
+ }
+ expr := p.followArithm(leftBrack, lpos)
+ p.quote = old
+ p.matchedArithm(lpos, leftBrack, rightBrack)
+ return expr
+}
+
+func (p *Parser) stopToken() bool {
+ switch p.tok {
+ case _EOF, _Newl, semicolon, and, or, andAnd, orOr, orAnd, dblSemicolon,
+ semiAnd, dblSemiAnd, semiOr, rightParen:
+ return true
+ case bckQuote:
+ return p.backquoteEnd()
+ }
+ return false
+}
+
+func (p *Parser) backquoteEnd() bool {
+ return p.lastBquoteEsc < p.openBquotes
+}
+
+// ValidName returns whether val is a valid name as per the POSIX spec.
+func ValidName(val string) bool {
+ if val == "" {
+ return false
+ }
+ for i, r := range val {
+ switch {
+ case 'a' <= r && r <= 'z':
+ case 'A' <= r && r <= 'Z':
+ case r == '_':
+ case i > 0 && '0' <= r && r <= '9':
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+func numberLiteral(val string) bool {
+ for _, r := range val {
+ if '0' > r || r > '9' {
+ return false
+ }
+ }
+ return true
+}
+
+func (p *Parser) hasValidIdent() bool {
+ if p.tok != _Lit && p.tok != _LitWord {
+ return false
+ }
+ if end := p.eqlOffs; end > 0 {
+ if p.val[end-1] == '+' && p.lang != LangPOSIX {
+ end-- // a+=x
+ }
+ if ValidName(p.val[:end]) {
+ return true
+ }
+ } else if !ValidName(p.val) {
+ return false // *[i]=x
+ }
+ return p.r == '[' // a[i]=x
+}
+
+func (p *Parser) getAssign(needEqual bool) *Assign {
+ as := &Assign{}
+ if p.eqlOffs > 0 { // foo=bar
+ nameEnd := p.eqlOffs
+ if p.lang != LangPOSIX && p.val[p.eqlOffs-1] == '+' {
+ // a+=b
+ as.Append = true
+ nameEnd--
+ }
+ as.Name = p.lit(p.pos, p.val[:nameEnd])
+ // since we're not using the entire p.val
+ as.Name.ValueEnd = posAddCol(as.Name.ValuePos, nameEnd)
+ left := p.lit(posAddCol(p.pos, 1), p.val[p.eqlOffs+1:])
+ if left.Value != "" {
+ left.ValuePos = posAddCol(left.ValuePos, p.eqlOffs)
+ as.Value = p.wordOne(left)
+ }
+ p.next()
+ } else { // foo[x]=bar
+ as.Name = p.lit(p.pos, p.val)
+ // hasValidIdent already checks p.r is '['
+ p.rune()
+ p.pos = posAddCol(p.pos, 1)
+ as.Index = p.eitherIndex()
+ if p.spaced || p.stopToken() {
+ if needEqual {
+ p.followErr(as.Pos(), "a[b]", "=")
+ } else {
+ as.Naked = true
+ return as
+ }
+ }
+ if len(p.val) > 0 && p.val[0] == '+' {
+ as.Append = true
+ p.val = p.val[1:]
+ p.pos = posAddCol(p.pos, 1)
+ }
+ if len(p.val) < 1 || p.val[0] != '=' {
+ if as.Append {
+ p.followErr(as.Pos(), "a[b]+", "=")
+ } else {
+ p.followErr(as.Pos(), "a[b]", "=")
+ }
+ return nil
+ }
+ p.pos = posAddCol(p.pos, 1)
+ p.val = p.val[1:]
+ if p.val == "" {
+ p.next()
+ }
+ }
+ if p.spaced || p.stopToken() {
+ return as
+ }
+ if as.Value == nil && p.tok == leftParen {
+ if p.lang == LangPOSIX {
+ p.langErr(p.pos, "arrays", LangBash, LangMirBSDKorn)
+ }
+ if as.Index != nil {
+ p.curErr("arrays cannot be nested")
+ }
+ as.Array = &ArrayExpr{Lparen: p.pos}
+ newQuote := p.quote
+ if p.lang.isBash() {
+ newQuote = arrayElems
+ }
+ old := p.preNested(newQuote)
+ p.next()
+ p.got(_Newl)
+ for p.tok != _EOF && p.tok != rightParen {
+ ae := &ArrayElem{}
+ ae.Comments, p.accComs = p.accComs, nil
+ if p.tok == leftBrack {
+ left := p.pos
+ ae.Index = p.eitherIndex()
+ p.follow(left, `"[x]"`, assgn)
+ }
+ if ae.Value = p.getWord(); ae.Value == nil {
+ switch p.tok {
+ case leftParen:
+ p.curErr("arrays cannot be nested")
+ return nil
+ case _Newl, rightParen, leftBrack:
+ // TODO: support [index]=[
+ default:
+ p.curErr("array element values must be words")
+ return nil
+ }
+ }
+ if len(p.accComs) > 0 {
+ c := p.accComs[0]
+ if c.Pos().Line() == ae.End().Line() {
+ ae.Comments = append(ae.Comments, c)
+ p.accComs = p.accComs[1:]
+ }
+ }
+ as.Array.Elems = append(as.Array.Elems, ae)
+ p.got(_Newl)
+ }
+ as.Array.Last, p.accComs = p.accComs, nil
+ p.postNested(old)
+ as.Array.Rparen = p.matched(as.Array.Lparen, leftParen, rightParen)
+ } else if w := p.getWord(); w != nil {
+ if as.Value == nil {
+ as.Value = w
+ } else {
+ as.Value.Parts = append(as.Value.Parts, w.Parts...)
+ }
+ }
+ return as
+}
+
+func (p *Parser) peekRedir() bool {
+ switch p.tok {
+ case rdrOut, appOut, rdrIn, dplIn, dplOut, clbOut, rdrInOut,
+ hdoc, dashHdoc, wordHdoc, rdrAll, appAll, _LitRedir:
+ return true
+ }
+ return false
+}
+
+func (p *Parser) doRedirect(s *Stmt) {
+ var r *Redirect
+ if s.Redirs == nil {
+ var alloc struct {
+ redirs [4]*Redirect
+ redir Redirect
+ }
+ s.Redirs = alloc.redirs[:0]
+ r = &alloc.redir
+ s.Redirs = append(s.Redirs, r)
+ } else {
+ r = &Redirect{}
+ s.Redirs = append(s.Redirs, r)
+ }
+ r.N = p.getLit()
+ if !p.lang.isBash() && r.N != nil && r.N.Value[0] == '{' {
+ p.langErr(r.N.Pos(), "{varname} redirects", LangBash)
+ }
+ r.Op, r.OpPos = RedirOperator(p.tok), p.pos
+ p.next()
+ switch r.Op {
+ case Hdoc, DashHdoc:
+ old := p.quote
+ p.quote, p.forbidNested = hdocWord, true
+ p.heredocs = append(p.heredocs, r)
+ r.Word = p.followWordTok(token(r.Op), r.OpPos)
+ p.quote, p.forbidNested = old, false
+ if p.tok == _Newl {
+ if len(p.accComs) > 0 {
+ c := p.accComs[0]
+ if c.Pos().Line() == s.End().Line() {
+ s.Comments = append(s.Comments, c)
+ p.accComs = p.accComs[1:]
+ }
+ }
+ p.doHeredocs()
+ }
+ case WordHdoc:
+ if p.lang == LangPOSIX {
+ p.langErr(r.OpPos, "herestrings", LangBash, LangMirBSDKorn)
+ }
+ fallthrough
+ default:
+ r.Word = p.followWordTok(token(r.Op), r.OpPos)
+ }
+}
+
+func (p *Parser) getStmt(readEnd, binCmd, fnBody bool) *Stmt {
+ pos, ok := p.gotRsrv("!")
+ s := p.stmt(pos)
+ if ok {
+ s.Negated = true
+ if p.stopToken() {
+ p.posErr(s.Pos(), `"!" cannot form a statement alone`)
+ }
+ if _, ok := p.gotRsrv("!"); ok {
+ p.posErr(s.Pos(), `cannot negate a command multiple times`)
+ }
+ }
+ if s = p.gotStmtPipe(s, false); s == nil || p.err != nil {
+ return nil
+ }
+ // instead of using recursion, iterate manually
+ for p.tok == andAnd || p.tok == orOr {
+ if binCmd {
+ // left associativity: in a list of BinaryCmds, the
+ // right recursion should only read a single element
+ return s
+ }
+ b := &BinaryCmd{
+ OpPos: p.pos,
+ Op: BinCmdOperator(p.tok),
+ X: s,
+ }
+ p.next()
+ p.got(_Newl)
+ b.Y = p.getStmt(false, true, false)
+ if b.Y == nil || p.err != nil {
+ p.followErr(b.OpPos, b.Op.String(), "a statement")
+ return nil
+ }
+ s = p.stmt(s.Position)
+ s.Cmd = b
+ s.Comments, b.X.Comments = b.X.Comments, nil
+ }
+ if readEnd {
+ switch p.tok {
+ case semicolon:
+ s.Semicolon = p.pos
+ p.next()
+ case and:
+ s.Semicolon = p.pos
+ p.next()
+ s.Background = true
+ case orAnd:
+ s.Semicolon = p.pos
+ p.next()
+ s.Coprocess = true
+ }
+ }
+ if len(p.accComs) > 0 && !binCmd && !fnBody {
+ c := p.accComs[0]
+ if c.Pos().Line() == s.End().Line() {
+ s.Comments = append(s.Comments, c)
+ p.accComs = p.accComs[1:]
+ }
+ }
+ return s
+}
+
+func (p *Parser) gotStmtPipe(s *Stmt, binCmd bool) *Stmt {
+ s.Comments, p.accComs = p.accComs, nil
+ switch p.tok {
+ case _LitWord:
+ switch p.val {
+ case "{":
+ p.block(s)
+ case "if":
+ p.ifClause(s)
+ case "while", "until":
+ p.whileClause(s, p.val == "until")
+ case "for":
+ p.forClause(s)
+ case "case":
+ p.caseClause(s)
+ case "}":
+ p.curErr(`%q can only be used to close a block`, p.val)
+ case "then":
+ p.curErr(`%q can only be used in an if`, p.val)
+ case "elif":
+ p.curErr(`%q can only be used in an if`, p.val)
+ case "fi":
+ p.curErr(`%q can only be used to end an if`, p.val)
+ case "do":
+ p.curErr(`%q can only be used in a loop`, p.val)
+ case "done":
+ p.curErr(`%q can only be used to end a loop`, p.val)
+ case "esac":
+ p.curErr(`%q can only be used to end a case`, p.val)
+ case "!":
+ if !s.Negated {
+ p.curErr(`"!" can only be used in full statements`)
+ break
+ }
+ case "[[":
+ if p.lang != LangPOSIX {
+ p.testClause(s)
+ }
+ case "]]":
+ if p.lang != LangPOSIX {
+ p.curErr(`%q can only be used to close a test`, p.val)
+ }
+ case "let":
+ if p.lang != LangPOSIX {
+ p.letClause(s)
+ }
+ case "function":
+ if p.lang != LangPOSIX {
+ p.bashFuncDecl(s)
+ }
+ case "declare":
+ if p.lang.isBash() { // Note that mksh lacks this one.
+ p.declClause(s)
+ }
+ case "local", "export", "readonly", "typeset", "nameref":
+ if p.lang != LangPOSIX {
+ p.declClause(s)
+ }
+ case "time":
+ if p.lang != LangPOSIX {
+ p.timeClause(s)
+ }
+ case "coproc":
+ if p.lang.isBash() { // Note that mksh lacks this one.
+ p.coprocClause(s)
+ }
+ case "select":
+ if p.lang != LangPOSIX {
+ p.selectClause(s)
+ }
+ case "@test":
+ if p.lang == LangBats {
+ p.testDecl(s)
+ }
+ }
+ if s.Cmd != nil {
+ break
+ }
+ if p.hasValidIdent() {
+ p.callExpr(s, nil, true)
+ break
+ }
+ name := p.lit(p.pos, p.val)
+ if p.next(); p.got(leftParen) {
+ p.follow(name.ValuePos, "foo(", rightParen)
+ if p.lang == LangPOSIX && !ValidName(name.Value) {
+ p.posErr(name.Pos(), "invalid func name")
+ }
+ p.funcDecl(s, name, name.ValuePos, true)
+ } else {
+ p.callExpr(s, p.wordOne(name), false)
+ }
+ case rdrOut, appOut, rdrIn, dplIn, dplOut, clbOut, rdrInOut,
+ hdoc, dashHdoc, wordHdoc, rdrAll, appAll, _LitRedir:
+ p.doRedirect(s)
+ p.callExpr(s, nil, false)
+ case bckQuote:
+ if p.backquoteEnd() {
+ return nil
+ }
+ fallthrough
+ case _Lit, dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut,
+ sglQuote, dollSglQuote, dblQuote, dollDblQuote, dollBrack,
+ globQuest, globStar, globPlus, globAt, globExcl:
+ if p.hasValidIdent() {
+ p.callExpr(s, nil, true)
+ break
+ }
+ w := p.wordAnyNumber()
+ if p.got(leftParen) {
+ p.posErr(w.Pos(), "invalid func name")
+ }
+ p.callExpr(s, w, false)
+ case leftParen:
+ p.subshell(s)
+ case dblLeftParen:
+ p.arithmExpCmd(s)
+ default:
+ if len(s.Redirs) == 0 {
+ return nil
+ }
+ }
+ for p.peekRedir() {
+ p.doRedirect(s)
+ }
+ // instead of using recursion, iterate manually
+ for p.tok == or || p.tok == orAnd {
+ if binCmd {
+ // left associativity: in a list of BinaryCmds, the
+ // right recursion should only read a single element
+ return s
+ }
+ if p.tok == orAnd && p.lang == LangMirBSDKorn {
+ // No need to check for LangPOSIX, as on that language
+ // we parse |& as two tokens.
+ break
+ }
+ b := &BinaryCmd{OpPos: p.pos, Op: BinCmdOperator(p.tok), X: s}
+ p.next()
+ p.got(_Newl)
+ if b.Y = p.gotStmtPipe(p.stmt(p.pos), true); b.Y == nil || p.err != nil {
+ p.followErr(b.OpPos, b.Op.String(), "a statement")
+ break
+ }
+ s = p.stmt(s.Position)
+ s.Cmd = b
+ s.Comments, b.X.Comments = b.X.Comments, nil
+ // in "! x | y", the bang applies to the entire pipeline
+ s.Negated = b.X.Negated
+ b.X.Negated = false
+ }
+ return s
+}
+
+func (p *Parser) subshell(s *Stmt) {
+ sub := &Subshell{Lparen: p.pos}
+ old := p.preNested(subCmd)
+ p.next()
+ sub.Stmts, sub.Last = p.stmtList()
+ p.postNested(old)
+ sub.Rparen = p.matched(sub.Lparen, leftParen, rightParen)
+ s.Cmd = sub
+}
+
+func (p *Parser) arithmExpCmd(s *Stmt) {
+ ar := &ArithmCmd{Left: p.pos}
+ old := p.preNested(arithmExprCmd)
+ p.next()
+ if p.got(hash) {
+ if p.lang != LangMirBSDKorn {
+ p.langErr(ar.Pos(), "unsigned expressions", LangMirBSDKorn)
+ }
+ ar.Unsigned = true
+ }
+ ar.X = p.followArithm(dblLeftParen, ar.Left)
+ ar.Right = p.arithmEnd(dblLeftParen, ar.Left, old)
+ s.Cmd = ar
+}
+
+func (p *Parser) block(s *Stmt) {
+ b := &Block{Lbrace: p.pos}
+ p.next()
+ b.Stmts, b.Last = p.stmtList("}")
+ pos, ok := p.gotRsrv("}")
+ b.Rbrace = pos
+ if !ok {
+ p.matchingErr(b.Lbrace, "{", "}")
+ }
+ s.Cmd = b
+}
+
+func (p *Parser) ifClause(s *Stmt) {
+ rootIf := &IfClause{Position: p.pos}
+ p.next()
+ rootIf.Cond, rootIf.CondLast = p.followStmts("if", rootIf.Position, "then")
+ rootIf.ThenPos = p.followRsrv(rootIf.Position, "if ", "then")
+ rootIf.Then, rootIf.ThenLast = p.followStmts("then", rootIf.ThenPos, "fi", "elif", "else")
+ curIf := rootIf
+ for p.tok == _LitWord && p.val == "elif" {
+ elf := &IfClause{Position: p.pos}
+ curIf.Last = p.accComs
+ p.accComs = nil
+ p.next()
+ elf.Cond, elf.CondLast = p.followStmts("elif", elf.Position, "then")
+ elf.ThenPos = p.followRsrv(elf.Position, "elif ", "then")
+ elf.Then, elf.ThenLast = p.followStmts("then", elf.ThenPos, "fi", "elif", "else")
+ curIf.Else = elf
+ curIf = elf
+ }
+ if elsePos, ok := p.gotRsrv("else"); ok {
+ curIf.Last = p.accComs
+ p.accComs = nil
+ els := &IfClause{Position: elsePos}
+ els.Then, els.ThenLast = p.followStmts("else", els.Position, "fi")
+ curIf.Else = els
+ curIf = els
+ }
+ curIf.Last = p.accComs
+ p.accComs = nil
+ rootIf.FiPos = p.stmtEnd(rootIf, "if", "fi")
+ for els := rootIf.Else; els != nil; els = els.Else {
+ // All the nested IfClauses share the same FiPos.
+ els.FiPos = rootIf.FiPos
+ }
+ s.Cmd = rootIf
+}
+
+func (p *Parser) whileClause(s *Stmt, until bool) {
+ wc := &WhileClause{WhilePos: p.pos, Until: until}
+ rsrv := "while"
+ rsrvCond := "while "
+ if wc.Until {
+ rsrv = "until"
+ rsrvCond = "until "
+ }
+ p.next()
+ wc.Cond, wc.CondLast = p.followStmts(rsrv, wc.WhilePos, "do")
+ wc.DoPos = p.followRsrv(wc.WhilePos, rsrvCond, "do")
+ wc.Do, wc.DoLast = p.followStmts("do", wc.DoPos, "done")
+ wc.DonePos = p.stmtEnd(wc, rsrv, "done")
+ s.Cmd = wc
+}
+
+func (p *Parser) forClause(s *Stmt) {
+ fc := &ForClause{ForPos: p.pos}
+ p.next()
+ fc.Loop = p.loop(fc.ForPos)
+
+ start, end := "do", "done"
+ if pos, ok := p.gotRsrv("{"); ok {
+ if p.lang == LangPOSIX {
+ p.langErr(pos, "for loops with braces", LangBash, LangMirBSDKorn)
+ }
+ fc.DoPos = pos
+ fc.Braces = true
+ start, end = "{", "}"
+ } else {
+ fc.DoPos = p.followRsrv(fc.ForPos, "for foo [in words]", start)
+ }
+
+ s.Comments = append(s.Comments, p.accComs...)
+ p.accComs = nil
+ fc.Do, fc.DoLast = p.followStmts(start, fc.DoPos, end)
+ fc.DonePos = p.stmtEnd(fc, "for", end)
+ s.Cmd = fc
+}
+
+func (p *Parser) loop(fpos Pos) Loop {
+ if !p.lang.isBash() {
+ switch p.tok {
+ case leftParen, dblLeftParen:
+ p.langErr(p.pos, "c-style fors", LangBash)
+ }
+ }
+ if p.tok == dblLeftParen {
+ cl := &CStyleLoop{Lparen: p.pos}
+ old := p.preNested(arithmExprCmd)
+ p.next()
+ cl.Init = p.arithmExpr(false)
+ if !p.got(dblSemicolon) {
+ p.follow(p.pos, "expr", semicolon)
+ cl.Cond = p.arithmExpr(false)
+ p.follow(p.pos, "expr", semicolon)
+ }
+ cl.Post = p.arithmExpr(false)
+ cl.Rparen = p.arithmEnd(dblLeftParen, cl.Lparen, old)
+ p.got(semicolon)
+ p.got(_Newl)
+ return cl
+ }
+ return p.wordIter("for", fpos)
+}
+
+func (p *Parser) wordIter(ftok string, fpos Pos) *WordIter {
+ wi := &WordIter{}
+ if wi.Name = p.getLit(); wi.Name == nil {
+ p.followErr(fpos, ftok, "a literal")
+ }
+ if p.got(semicolon) {
+ p.got(_Newl)
+ return wi
+ }
+ p.got(_Newl)
+ if pos, ok := p.gotRsrv("in"); ok {
+ wi.InPos = pos
+ for !p.stopToken() {
+ if w := p.getWord(); w == nil {
+ p.curErr("word list can only contain words")
+ } else {
+ wi.Items = append(wi.Items, w)
+ }
+ }
+ p.got(semicolon)
+ p.got(_Newl)
+ } else if p.tok == _LitWord && p.val == "do" {
+ } else {
+ p.followErr(fpos, ftok+" foo", `"in", "do", ;, or a newline`)
+ }
+ return wi
+}
+
+func (p *Parser) selectClause(s *Stmt) {
+ fc := &ForClause{ForPos: p.pos, Select: true}
+ p.next()
+ fc.Loop = p.wordIter("select", fc.ForPos)
+ fc.DoPos = p.followRsrv(fc.ForPos, "select foo [in words]", "do")
+ fc.Do, fc.DoLast = p.followStmts("do", fc.DoPos, "done")
+ fc.DonePos = p.stmtEnd(fc, "select", "done")
+ s.Cmd = fc
+}
+
+func (p *Parser) caseClause(s *Stmt) {
+ cc := &CaseClause{Case: p.pos}
+ p.next()
+ cc.Word = p.getWord()
+ if cc.Word == nil {
+ p.followErr(cc.Case, "case", "a word")
+ }
+ end := "esac"
+ p.got(_Newl)
+ if pos, ok := p.gotRsrv("{"); ok {
+ cc.In = pos
+ cc.Braces = true
+ if p.lang != LangMirBSDKorn {
+ p.posErr(cc.Pos(), `"case i {" is a mksh feature`)
+ }
+ end = "}"
+ } else {
+ cc.In = p.followRsrv(cc.Case, "case x", "in")
+ }
+ cc.Items = p.caseItems(end)
+ cc.Last, p.accComs = p.accComs, nil
+ cc.Esac = p.stmtEnd(cc, "case", end)
+ s.Cmd = cc
+}
+
+func (p *Parser) caseItems(stop string) (items []*CaseItem) {
+ p.got(_Newl)
+ for p.tok != _EOF && !(p.tok == _LitWord && p.val == stop) {
+ ci := &CaseItem{}
+ ci.Comments, p.accComs = p.accComs, nil
+ p.got(leftParen)
+ for p.tok != _EOF {
+ if w := p.getWord(); w == nil {
+ p.curErr("case patterns must consist of words")
+ } else {
+ ci.Patterns = append(ci.Patterns, w)
+ }
+ if p.tok == rightParen {
+ break
+ }
+ if !p.got(or) {
+ p.curErr("case patterns must be separated with |")
+ }
+ }
+ old := p.preNested(switchCase)
+ p.next()
+ ci.Stmts, ci.Last = p.stmtList(stop)
+ p.postNested(old)
+ switch p.tok {
+ case dblSemicolon, semiAnd, dblSemiAnd, semiOr:
+ default:
+ ci.Op = Break
+ items = append(items, ci)
+ return
+ }
+ ci.Last = append(ci.Last, p.accComs...)
+ p.accComs = nil
+ ci.OpPos = p.pos
+ ci.Op = CaseOperator(p.tok)
+ p.next()
+ p.got(_Newl)
+
+ // Split the comments:
+ //
+ // case x in
+ // a)
+ // foo
+ // ;;
+ // # comment for a
+ // # comment for b
+ // b)
+ // [...]
+ split := len(p.accComs)
+ for i := len(p.accComs) - 1; i >= 0; i-- {
+ c := p.accComs[i]
+ if c.Pos().Col() != p.pos.Col() {
+ break
+ }
+ split = i
+ }
+ ci.Comments = append(ci.Comments, p.accComs[:split]...)
+ p.accComs = p.accComs[split:]
+
+ items = append(items, ci)
+ }
+ return
+}
+
+func (p *Parser) testClause(s *Stmt) {
+ tc := &TestClause{Left: p.pos}
+ old := p.preNested(testExpr)
+ p.next()
+ if _, ok := p.gotRsrv("]]"); ok || p.tok == _EOF {
+ p.posErr(tc.Left, "test clause requires at least one expression")
+ }
+ tc.X = p.testExpr(dblLeftBrack, tc.Left, false)
+ if tc.X == nil {
+ p.followErrExp(tc.Left, "[[")
+ }
+ tc.Right = p.pos
+ if _, ok := p.gotRsrv("]]"); !ok {
+ p.matchingErr(tc.Left, "[[", "]]")
+ }
+ p.postNested(old)
+ s.Cmd = tc
+}
+
+func (p *Parser) testExpr(ftok token, fpos Pos, pastAndOr bool) TestExpr {
+ p.got(_Newl)
+ var left TestExpr
+ if pastAndOr {
+ left = p.testExprBase()
+ } else {
+ left = p.testExpr(ftok, fpos, true)
+ }
+ if left == nil {
+ return left
+ }
+ p.got(_Newl)
+ switch p.tok {
+ case andAnd, orOr:
+ case _LitWord:
+ if p.val == "]]" {
+ return left
+ }
+ if p.tok = token(testBinaryOp(p.val)); p.tok == illegalTok {
+ p.curErr("not a valid test operator: %s", p.val)
+ }
+ case rdrIn, rdrOut:
+ case _EOF, rightParen:
+ return left
+ case _Lit:
+ p.curErr("test operator words must consist of a single literal")
+ default:
+ p.curErr("not a valid test operator: %v", p.tok)
+ }
+ b := &BinaryTest{
+ OpPos: p.pos,
+ Op: BinTestOperator(p.tok),
+ X: left,
+ }
+ // Save the previous quoteState, since we change it in TsReMatch.
+ oldQuote := p.quote
+
+ switch b.Op {
+ case AndTest, OrTest:
+ p.next()
+ if b.Y = p.testExpr(token(b.Op), b.OpPos, false); b.Y == nil {
+ p.followErrExp(b.OpPos, b.Op.String())
+ }
+ case TsReMatch:
+ if !p.lang.isBash() {
+ p.langErr(p.pos, "regex tests", LangBash)
+ }
+ p.rxOpenParens = 0
+ p.rxFirstPart = true
+ // TODO(mvdan): Using nested states within a regex will break in
+ // all sorts of ways. The better fix is likely to use a stop
+ // token, like we do with heredocs.
+ p.quote = testExprRegexp
+ fallthrough
+ default:
+ if _, ok := b.X.(*Word); !ok {
+ p.posErr(b.OpPos, "expected %s, %s or %s after complex expr",
+ AndTest, OrTest, "]]")
+ }
+ p.next()
+ b.Y = p.followWordTok(token(b.Op), b.OpPos)
+ }
+ p.quote = oldQuote
+ return b
+}
+
+func (p *Parser) testExprBase() TestExpr {
+ switch p.tok {
+ case _EOF, rightParen:
+ return nil
+ case _LitWord:
+ op := token(testUnaryOp(p.val))
+ switch op {
+ case illegalTok:
+ case tsRefVar, tsModif: // not available in mksh
+ if p.lang.isBash() {
+ p.tok = op
+ }
+ default:
+ p.tok = op
+ }
+ }
+ switch p.tok {
+ case exclMark:
+ u := &UnaryTest{OpPos: p.pos, Op: TsNot}
+ p.next()
+ if u.X = p.testExpr(token(u.Op), u.OpPos, false); u.X == nil {
+ p.followErrExp(u.OpPos, u.Op.String())
+ }
+ return u
+ case tsExists, tsRegFile, tsDirect, tsCharSp, tsBlckSp, tsNmPipe,
+ tsSocket, tsSmbLink, tsSticky, tsGIDSet, tsUIDSet, tsGrpOwn,
+ tsUsrOwn, tsModif, tsRead, tsWrite, tsExec, tsNoEmpty,
+ tsFdTerm, tsEmpStr, tsNempStr, tsOptSet, tsVarSet, tsRefVar:
+ u := &UnaryTest{OpPos: p.pos, Op: UnTestOperator(p.tok)}
+ p.next()
+ u.X = p.followWordTok(token(u.Op), u.OpPos)
+ return u
+ case leftParen:
+ pe := &ParenTest{Lparen: p.pos}
+ p.next()
+ if pe.X = p.testExpr(leftParen, pe.Lparen, false); pe.X == nil {
+ p.followErrExp(pe.Lparen, "(")
+ }
+ pe.Rparen = p.matched(pe.Lparen, leftParen, rightParen)
+ return pe
+ case _LitWord:
+ if p.val == "]]" {
+ return nil
+ }
+ fallthrough
+ default:
+ if w := p.getWord(); w != nil {
+ return w
+ }
+ // otherwise we'd return a typed nil above
+ return nil
+ }
+}
+
+func (p *Parser) declClause(s *Stmt) {
+ ds := &DeclClause{Variant: p.lit(p.pos, p.val)}
+ p.next()
+ for !p.stopToken() && !p.peekRedir() {
+ if p.hasValidIdent() {
+ ds.Args = append(ds.Args, p.getAssign(false))
+ } else if p.eqlOffs > 0 {
+ p.curErr("invalid var name")
+ } else if p.tok == _LitWord && ValidName(p.val) {
+ ds.Args = append(ds.Args, &Assign{
+ Naked: true,
+ Name: p.getLit(),
+ })
+ } else if w := p.getWord(); w != nil {
+ ds.Args = append(ds.Args, &Assign{
+ Naked: true,
+ Value: w,
+ })
+ } else {
+ p.followErr(p.pos, ds.Variant.Value, "names or assignments")
+ }
+ }
+ s.Cmd = ds
+}
+
+func isBashCompoundCommand(tok token, val string) bool {
+ switch tok {
+ case leftParen, dblLeftParen:
+ return true
+ case _LitWord:
+ switch val {
+ case "{", "if", "while", "until", "for", "case", "[[",
+ "coproc", "let", "function", "declare", "local",
+ "export", "readonly", "typeset", "nameref":
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) timeClause(s *Stmt) {
+ tc := &TimeClause{Time: p.pos}
+ p.next()
+ if _, ok := p.gotRsrv("-p"); ok {
+ tc.PosixFormat = true
+ }
+ tc.Stmt = p.gotStmtPipe(p.stmt(p.pos), false)
+ s.Cmd = tc
+}
+
+func (p *Parser) coprocClause(s *Stmt) {
+ cc := &CoprocClause{Coproc: p.pos}
+ if p.next(); isBashCompoundCommand(p.tok, p.val) {
+ // has no name
+ cc.Stmt = p.gotStmtPipe(p.stmt(p.pos), false)
+ s.Cmd = cc
+ return
+ }
+ cc.Name = p.getWord()
+ cc.Stmt = p.gotStmtPipe(p.stmt(p.pos), false)
+ if cc.Stmt == nil {
+ if cc.Name == nil {
+ p.posErr(cc.Coproc, "coproc clause requires a command")
+ return
+ }
+ // name was in fact the stmt
+ cc.Stmt = p.stmt(cc.Name.Pos())
+ cc.Stmt.Cmd = p.call(cc.Name)
+ cc.Name = nil
+ } else if cc.Name != nil {
+ if call, ok := cc.Stmt.Cmd.(*CallExpr); ok {
+ // name was in fact the start of a call
+ call.Args = append([]*Word{cc.Name}, call.Args...)
+ cc.Name = nil
+ }
+ }
+ s.Cmd = cc
+}
+
+func (p *Parser) letClause(s *Stmt) {
+ lc := &LetClause{Let: p.pos}
+ old := p.preNested(arithmExprLet)
+ p.next()
+ for !p.stopToken() && !p.peekRedir() {
+ x := p.arithmExpr(true)
+ if x == nil {
+ break
+ }
+ lc.Exprs = append(lc.Exprs, x)
+ }
+ if len(lc.Exprs) == 0 {
+ p.followErrExp(lc.Let, "let")
+ }
+ p.postNested(old)
+ s.Cmd = lc
+}
+
+func (p *Parser) bashFuncDecl(s *Stmt) {
+ fpos := p.pos
+ if p.next(); p.tok != _LitWord {
+ p.followErr(fpos, "function", "a name")
+ }
+ name := p.lit(p.pos, p.val)
+ hasParens := false
+ if p.next(); p.got(leftParen) {
+ hasParens = true
+ p.follow(name.ValuePos, "foo(", rightParen)
+ }
+ p.funcDecl(s, name, fpos, hasParens)
+}
+
+func (p *Parser) testDecl(s *Stmt) {
+ td := &TestDecl{Position: p.pos}
+ p.next()
+ if td.Description = p.getWord(); td.Description == nil {
+ p.followErr(td.Position, "@test", "a description word")
+ }
+ if td.Body = p.getStmt(false, false, true); td.Body == nil {
+ p.followErr(td.Position, `@test "desc"`, "a statement")
+ }
+ s.Cmd = td
+}
+
+func (p *Parser) callExpr(s *Stmt, w *Word, assign bool) {
+ ce := p.call(w)
+ if w == nil {
+ ce.Args = ce.Args[:0]
+ }
+ if assign {
+ ce.Assigns = append(ce.Assigns, p.getAssign(true))
+ }
+loop:
+ for {
+ switch p.tok {
+ case _EOF, _Newl, semicolon, and, or, andAnd, orOr, orAnd,
+ dblSemicolon, semiAnd, dblSemiAnd, semiOr:
+ break loop
+ case _LitWord:
+ if len(ce.Args) == 0 && p.hasValidIdent() {
+ ce.Assigns = append(ce.Assigns, p.getAssign(true))
+ break
+ }
+ ce.Args = append(ce.Args, p.wordOne(p.lit(p.pos, p.val)))
+ p.next()
+ case _Lit:
+ if len(ce.Args) == 0 && p.hasValidIdent() {
+ ce.Assigns = append(ce.Assigns, p.getAssign(true))
+ break
+ }
+ ce.Args = append(ce.Args, p.wordAnyNumber())
+ case bckQuote:
+ if p.backquoteEnd() {
+ break loop
+ }
+ fallthrough
+ case dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut,
+ sglQuote, dollSglQuote, dblQuote, dollDblQuote, dollBrack,
+ globQuest, globStar, globPlus, globAt, globExcl:
+ ce.Args = append(ce.Args, p.wordAnyNumber())
+ case rdrOut, appOut, rdrIn, dplIn, dplOut, clbOut, rdrInOut,
+ hdoc, dashHdoc, wordHdoc, rdrAll, appAll, _LitRedir:
+ p.doRedirect(s)
+ case dblLeftParen:
+ p.curErr("%s can only be used to open an arithmetic cmd", p.tok)
+ case rightParen:
+ if p.quote == subCmd {
+ break loop
+ }
+ fallthrough
+ default:
+ // Note that we'll only keep the first error that happens.
+ if len(ce.Args) > 0 {
+ if cmd := ce.Args[0].Lit(); p.lang == LangPOSIX && isBashCompoundCommand(_LitWord, cmd) {
+ p.curErr("the %q builtin exists in bash; tried parsing as posix", cmd)
+ }
+ }
+ p.curErr("a command can only contain words and redirects; encountered %s", p.tok)
+ }
+ }
+ if len(ce.Assigns) == 0 && len(ce.Args) == 0 {
+ return
+ }
+ if len(ce.Args) == 0 {
+ ce.Args = nil
+ } else {
+ for _, asgn := range ce.Assigns {
+ if asgn.Index != nil || asgn.Array != nil {
+ p.posErr(asgn.Pos(), "inline variables cannot be arrays")
+ }
+ }
+ }
+ s.Cmd = ce
+}
+
+func (p *Parser) funcDecl(s *Stmt, name *Lit, pos Pos, withParens bool) {
+ fd := &FuncDecl{
+ Position: pos,
+ RsrvWord: pos != name.ValuePos,
+ Parens: withParens,
+ Name: name,
+ }
+ p.got(_Newl)
+ if fd.Body = p.getStmt(false, false, true); fd.Body == nil {
+ p.followErr(fd.Pos(), "foo()", "a statement")
+ }
+ s.Cmd = fd
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/parser_arithm.go b/vendor/mvdan.cc/sh/v3/syntax/parser_arithm.go
new file mode 100644
index 00000000..a6d6a951
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/parser_arithm.go
@@ -0,0 +1,353 @@
+package syntax
+
+// compact specifies whether we allow spaces between expressions.
+// This is true for let
+func (p *Parser) arithmExpr(compact bool) ArithmExpr {
+ return p.arithmExprComma(compact)
+}
+
+// These function names are inspired by Bash's expr.c
+
+func (p *Parser) arithmExprComma(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprAssign, Comma)
+}
+
+func (p *Parser) arithmExprAssign(compact bool) ArithmExpr {
+ // Assign is different from the other binary operators because it's
+ // right-associative and needs to check that it's placed after a name
+ value := p.arithmExprTernary(compact)
+ switch BinAritOperator(p.tok) {
+ case AddAssgn, SubAssgn, MulAssgn, QuoAssgn, RemAssgn, AndAssgn,
+ OrAssgn, XorAssgn, ShlAssgn, ShrAssgn, Assgn:
+ if compact && p.spaced {
+ return value
+ }
+ if !isArithName(value) {
+ p.posErr(p.pos, "%s must follow a name", p.tok.String())
+ }
+ pos := p.pos
+ tok := p.tok
+ p.nextArithOp(compact)
+ y := p.arithmExprAssign(compact)
+ if y == nil {
+ p.followErrExp(pos, tok.String())
+ }
+ return &BinaryArithm{
+ OpPos: pos,
+ Op: BinAritOperator(tok),
+ X: value,
+ Y: y,
+ }
+ }
+ return value
+}
+
+func (p *Parser) arithmExprTernary(compact bool) ArithmExpr {
+ value := p.arithmExprLor(compact)
+ if BinAritOperator(p.tok) != TernQuest || (compact && p.spaced) {
+ return value
+ }
+
+ if value == nil {
+ p.curErr("%s must follow an expression", p.tok.String())
+ }
+ questPos := p.pos
+ p.nextArithOp(compact)
+ if BinAritOperator(p.tok) == TernColon {
+ p.followErrExp(questPos, TernQuest.String())
+ }
+ trueExpr := p.arithmExpr(compact)
+ if trueExpr == nil {
+ p.followErrExp(questPos, TernQuest.String())
+ }
+ if BinAritOperator(p.tok) != TernColon {
+ p.posErr(questPos, "ternary operator missing : after ?")
+ }
+ colonPos := p.pos
+ p.nextArithOp(compact)
+ falseExpr := p.arithmExprTernary(compact)
+ if falseExpr == nil {
+ p.followErrExp(colonPos, TernColon.String())
+ }
+ return &BinaryArithm{
+ OpPos: questPos,
+ Op: TernQuest,
+ X: value,
+ Y: &BinaryArithm{
+ OpPos: colonPos,
+ Op: TernColon,
+ X: trueExpr,
+ Y: falseExpr,
+ },
+ }
+}
+
+func (p *Parser) arithmExprLor(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprLand, OrArit)
+}
+
+func (p *Parser) arithmExprLand(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprBor, AndArit)
+}
+
+func (p *Parser) arithmExprBor(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprBxor, Or)
+}
+
+func (p *Parser) arithmExprBxor(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprBand, Xor)
+}
+
+func (p *Parser) arithmExprBand(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprEquality, And)
+}
+
+func (p *Parser) arithmExprEquality(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprComparison, Eql, Neq)
+}
+
+func (p *Parser) arithmExprComparison(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprShift, Lss, Gtr, Leq, Geq)
+}
+
+func (p *Parser) arithmExprShift(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprAddition, Shl, Shr)
+}
+
+func (p *Parser) arithmExprAddition(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprMultiplication, Add, Sub)
+}
+
+func (p *Parser) arithmExprMultiplication(compact bool) ArithmExpr {
+ return p.arithmExprBinary(compact, p.arithmExprPower, Mul, Quo, Rem)
+}
+
+func (p *Parser) arithmExprPower(compact bool) ArithmExpr {
+ // Power is different from the other binary operators because it's right-associative
+ value := p.arithmExprUnary(compact)
+ if BinAritOperator(p.tok) != Pow || (compact && p.spaced) {
+ return value
+ }
+
+ if value == nil {
+ p.curErr("%s must follow an expression", p.tok.String())
+ }
+
+ op := p.tok
+ pos := p.pos
+ p.nextArithOp(compact)
+ y := p.arithmExprPower(compact)
+ if y == nil {
+ p.followErrExp(pos, op.String())
+ }
+ return &BinaryArithm{
+ OpPos: pos,
+ Op: BinAritOperator(op),
+ X: value,
+ Y: y,
+ }
+}
+
+func (p *Parser) arithmExprUnary(compact bool) ArithmExpr {
+ if !compact {
+ p.got(_Newl)
+ }
+
+ switch UnAritOperator(p.tok) {
+ case Not, BitNegation, Plus, Minus:
+ ue := &UnaryArithm{OpPos: p.pos, Op: UnAritOperator(p.tok)}
+ p.nextArithOp(compact)
+ if ue.X = p.arithmExprUnary(compact); ue.X == nil {
+ p.followErrExp(ue.OpPos, ue.Op.String())
+ }
+ return ue
+ }
+ return p.arithmExprValue(compact)
+}
+
+func (p *Parser) arithmExprValue(compact bool) ArithmExpr {
+ var x ArithmExpr
+ switch p.tok {
+ case addAdd, subSub:
+ ue := &UnaryArithm{OpPos: p.pos, Op: UnAritOperator(p.tok)}
+ p.nextArith(compact)
+ if p.tok != _LitWord {
+ p.followErr(ue.OpPos, token(ue.Op).String(), "a literal")
+ }
+ ue.X = p.arithmExprValue(compact)
+ return ue
+ case leftParen:
+ pe := &ParenArithm{Lparen: p.pos}
+ p.nextArithOp(compact)
+ pe.X = p.followArithm(leftParen, pe.Lparen)
+ pe.Rparen = p.matched(pe.Lparen, leftParen, rightParen)
+ x = pe
+ case leftBrack:
+ p.curErr("[ must follow a name")
+ case colon:
+ p.curErr("ternary operator missing ? before :")
+ case _LitWord:
+ l := p.getLit()
+ if p.tok != leftBrack {
+ x = p.wordOne(l)
+ break
+ }
+ pe := &ParamExp{Dollar: l.ValuePos, Short: true, Param: l}
+ pe.Index = p.eitherIndex()
+ x = p.wordOne(pe)
+ case bckQuote:
+ if p.quote == arithmExprLet && p.openBquotes > 0 {
+ return nil
+ }
+ fallthrough
+ default:
+ if w := p.getWord(); w != nil {
+ x = w
+ } else {
+ return nil
+ }
+ }
+
+ if compact && p.spaced {
+ return x
+ }
+ if !compact {
+ p.got(_Newl)
+ }
+
+ // we want real nil, not (*Word)(nil) as that
+ // sets the type to non-nil and then x != nil
+ if p.tok == addAdd || p.tok == subSub {
+ if !isArithName(x) {
+ p.curErr("%s must follow a name", p.tok.String())
+ }
+ u := &UnaryArithm{
+ Post: true,
+ OpPos: p.pos,
+ Op: UnAritOperator(p.tok),
+ X: x,
+ }
+ p.nextArith(compact)
+ return u
+ }
+ return x
+}
+
+// nextArith consumes a token.
+// It returns true if compact and the token was followed by spaces
+func (p *Parser) nextArith(compact bool) bool {
+ p.next()
+ if compact && p.spaced {
+ return true
+ }
+ if !compact {
+ p.got(_Newl)
+ }
+ return false
+}
+
+func (p *Parser) nextArithOp(compact bool) {
+ pos := p.pos
+ tok := p.tok
+ if p.nextArith(compact) {
+ p.followErrExp(pos, tok.String())
+ }
+}
+
+// arithmExprBinary is used for all left-associative binary operators
+func (p *Parser) arithmExprBinary(compact bool, nextOp func(bool) ArithmExpr, operators ...BinAritOperator) ArithmExpr {
+ value := nextOp(compact)
+ for {
+ var foundOp BinAritOperator
+ for _, op := range operators {
+ if p.tok == token(op) {
+ foundOp = op
+ break
+ }
+ }
+
+ if token(foundOp) == illegalTok || (compact && p.spaced) {
+ return value
+ }
+
+ if value == nil {
+ p.curErr("%s must follow an expression", p.tok.String())
+ }
+
+ pos := p.pos
+ p.nextArithOp(compact)
+ y := nextOp(compact)
+ if y == nil {
+ p.followErrExp(pos, foundOp.String())
+ }
+
+ value = &BinaryArithm{
+ OpPos: pos,
+ Op: foundOp,
+ X: value,
+ Y: y,
+ }
+ }
+}
+
+func isArithName(left ArithmExpr) bool {
+ w, ok := left.(*Word)
+ if !ok || len(w.Parts) != 1 {
+ return false
+ }
+ switch x := w.Parts[0].(type) {
+ case *Lit:
+ return ValidName(x.Value)
+ case *ParamExp:
+ return x.nakedIndex()
+ default:
+ return false
+ }
+}
+
+func (p *Parser) followArithm(ftok token, fpos Pos) ArithmExpr {
+ x := p.arithmExpr(false)
+ if x == nil {
+ p.followErrExp(fpos, ftok.String())
+ }
+ return x
+}
+
+func (p *Parser) peekArithmEnd() bool {
+ return p.tok == rightParen && p.r == ')'
+}
+
+func (p *Parser) arithmMatchingErr(pos Pos, left, right token) {
+ switch p.tok {
+ case _Lit, _LitWord:
+ p.curErr("not a valid arithmetic operator: %s", p.val)
+ case leftBrack:
+ p.curErr("[ must follow a name")
+ case colon:
+ p.curErr("ternary operator missing ? before :")
+ case rightParen, _EOF:
+ p.matchingErr(pos, left, right)
+ default:
+ if p.quote == arithmExpr {
+ p.curErr("not a valid arithmetic operator: %v", p.tok)
+ }
+ p.matchingErr(pos, left, right)
+ }
+}
+
+func (p *Parser) matchedArithm(lpos Pos, left, right token) {
+ if !p.got(right) {
+ p.arithmMatchingErr(lpos, left, right)
+ }
+}
+
+func (p *Parser) arithmEnd(ltok token, lpos Pos, old saveState) Pos {
+ if !p.peekArithmEnd() {
+ p.arithmMatchingErr(lpos, ltok, dblRightParen)
+ }
+ p.rune()
+ p.postNested(old)
+ pos := p.pos
+ p.next()
+ return pos
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/printer.go b/vendor/mvdan.cc/sh/v3/syntax/printer.go
new file mode 100644
index 00000000..6626b363
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/printer.go
@@ -0,0 +1,1527 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+ "text/tabwriter"
+ "unicode"
+
+ "mvdan.cc/sh/v3/fileutil"
+)
+
+// PrinterOption is a function which can be passed to NewPrinter
+// to alter its behavior. To apply option to existing Printer
+// call it directly, for example KeepPadding(true)(printer).
+type PrinterOption func(*Printer)
+
+// Indent sets the number of spaces used for indentation. If set to 0,
+// tabs will be used instead.
+func Indent(spaces uint) PrinterOption {
+ return func(p *Printer) { p.indentSpaces = spaces }
+}
+
+// BinaryNextLine will make binary operators appear on the next line
+// when a binary command, such as a pipe, spans multiple lines. A
+// backslash will be used.
+func BinaryNextLine(enabled bool) PrinterOption {
+ return func(p *Printer) { p.binNextLine = enabled }
+}
+
+// SwitchCaseIndent will make switch cases be indented. As such, switch
+// case bodies will be two levels deeper than the switch itself.
+func SwitchCaseIndent(enabled bool) PrinterOption {
+ return func(p *Printer) { p.swtCaseIndent = enabled }
+}
+
+// TODO(v4): consider turning this into a "space all operators" option, to also
+// allow foo=( bar baz ), (( x + y )), and so on.
+
+// SpaceRedirects will put a space after most redirection operators. The
+// exceptions are '>&', '<&', '>(', and '<('.
+func SpaceRedirects(enabled bool) PrinterOption {
+ return func(p *Printer) { p.spaceRedirects = enabled }
+}
+
+// KeepPadding will keep most nodes and tokens in the same column that
+// they were in the original source. This allows the user to decide how
+// to align and pad their code with spaces.
+//
+// Note that this feature is best-effort and will only keep the
+// alignment stable, so it may need some human help the first time it is
+// run.
+func KeepPadding(enabled bool) PrinterOption {
+ return func(p *Printer) {
+ if enabled && !p.keepPadding {
+ // Enable the flag, and set up the writer wrapper.
+ p.keepPadding = true
+ p.cols.Writer = p.bufWriter.(*bufio.Writer)
+ p.bufWriter = &p.cols
+
+ } else if !enabled && p.keepPadding {
+ // Ensure we reset the state to that of NewPrinter.
+ p.keepPadding = false
+ p.bufWriter = p.cols.Writer
+ p.cols = colCounter{}
+ }
+ }
+}
+
+// Minify will print programs in a way to save the most bytes possible.
+// For example, indentation and comments are skipped, and extra
+// whitespace is avoided when possible.
+func Minify(enabled bool) PrinterOption {
+ return func(p *Printer) { p.minify = enabled }
+}
+
+// SingleLine will attempt to print programs in one line. For example, lists of
+// commands or nested blocks do not use newlines in this mode. Note that some
+// newlines must still appear, such as those following comments or around
+// here-documents.
+//
+// Print's trailing newline when given a *File is not affected by this option.
+func SingleLine(enabled bool) PrinterOption {
+ return func(p *Printer) { p.singleLine = enabled }
+}
+
+// FunctionNextLine will place a function's opening braces on the next line.
+func FunctionNextLine(enabled bool) PrinterOption {
+ return func(p *Printer) { p.funcNextLine = enabled }
+}
+
+// NewPrinter allocates a new Printer and applies any number of options.
+func NewPrinter(opts ...PrinterOption) *Printer {
+ p := &Printer{
+ bufWriter: bufio.NewWriter(nil),
+ tabWriter: new(tabwriter.Writer),
+ }
+ for _, opt := range opts {
+ opt(p)
+ }
+ return p
+}
+
+// Print "pretty-prints" the given syntax tree node to the given writer. Writes
+// to w are buffered.
+//
+// The node types supported at the moment are *File, *Stmt, *Word, *Assign, any
+// Command node, and any WordPart node. A trailing newline will only be printed
+// when a *File is used.
+func (p *Printer) Print(w io.Writer, node Node) error {
+ p.reset()
+
+ if p.minify && p.singleLine {
+ return fmt.Errorf("Minify and SingleLine together are not supported yet; please file an issue describing your use case: https://github.com/mvdan/sh/issues")
+ }
+
+ // TODO: consider adding a raw mode to skip the tab writer, much like in
+ // go/printer.
+ twmode := tabwriter.DiscardEmptyColumns | tabwriter.StripEscape
+ tabwidth := 8
+ if p.indentSpaces == 0 {
+ // indenting with tabs
+ twmode |= tabwriter.TabIndent
+ } else {
+ // indenting with spaces
+ tabwidth = int(p.indentSpaces)
+ }
+ p.tabWriter.Init(w, 0, tabwidth, 1, ' ', twmode)
+ w = p.tabWriter
+
+ p.bufWriter.Reset(w)
+ switch x := node.(type) {
+ case *File:
+ p.stmtList(x.Stmts, x.Last)
+ p.newline(Pos{})
+ case *Stmt:
+ p.stmtList([]*Stmt{x}, nil)
+ case Command:
+ p.command(x, nil)
+ case *Word:
+ p.line = x.Pos().Line()
+ p.word(x)
+ case WordPart:
+ p.line = x.Pos().Line()
+ p.wordPart(x, nil)
+ case *Assign:
+ p.line = x.Pos().Line()
+ p.assigns([]*Assign{x})
+ default:
+ return fmt.Errorf("unsupported node type: %T", x)
+ }
+ p.flushHeredocs()
+ p.flushComments()
+
+ // flush the writers
+ if err := p.bufWriter.Flush(); err != nil {
+ return err
+ }
+ if tw, _ := w.(*tabwriter.Writer); tw != nil {
+ if err := tw.Flush(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type bufWriter interface {
+ Write([]byte) (int, error)
+ WriteString(string) (int, error)
+ WriteByte(byte) error
+ Reset(io.Writer)
+ Flush() error
+}
+
+type colCounter struct {
+ *bufio.Writer
+ column int
+ lineStart bool
+}
+
+func (c *colCounter) addByte(b byte) {
+ switch b {
+ case '\n':
+ c.column = 0
+ c.lineStart = true
+ case '\t', ' ', tabwriter.Escape:
+ default:
+ c.lineStart = false
+ }
+ c.column++
+}
+
+func (c *colCounter) WriteByte(b byte) error {
+ c.addByte(b)
+ return c.Writer.WriteByte(b)
+}
+
+func (c *colCounter) WriteString(s string) (int, error) {
+ for _, b := range []byte(s) {
+ c.addByte(b)
+ }
+ return c.Writer.WriteString(s)
+}
+
+func (c *colCounter) Reset(w io.Writer) {
+ c.column = 1
+ c.lineStart = true
+ c.Writer.Reset(w)
+}
+
+// Printer holds the internal state of the printing mechanism of a
+// program.
+type Printer struct {
+ bufWriter
+ tabWriter *tabwriter.Writer
+ cols colCounter
+
+ indentSpaces uint
+ binNextLine bool
+ swtCaseIndent bool
+ spaceRedirects bool
+ keepPadding bool
+ minify bool
+ singleLine bool
+ funcNextLine bool
+
+ wantSpace wantSpaceState // whether space is required or has been written
+
+ wantNewline bool // newline is wanted for pretty-printing; ignored by singleLine; ignored by singleLine
+ mustNewline bool // newline is required to keep shell syntax valid
+ wroteSemi bool // wrote ';' for the current statement
+
+ // pendingComments are any comments in the current line or statement
+ // that we have yet to print. This is useful because that way, we can
+ // ensure that all comments are written immediately before a newline.
+ // Otherwise, in some edge cases we might wrongly place words after a
+ // comment in the same line, breaking programs.
+ pendingComments []Comment
+
+ // firstLine means we are still writing the first line
+ firstLine bool
+ // line is the current line number
+ line uint
+
+ // lastLevel is the last level of indentation that was used.
+ lastLevel uint
+ // level is the current level of indentation.
+ level uint
+ // levelIncs records which indentation level increments actually
+ // took place, to revert them once their section ends.
+ levelIncs []bool
+
+ nestedBinary bool
+
+ // pendingHdocs is the list of pending heredocs to write.
+ pendingHdocs []*Redirect
+
+ // used when printing <<- heredocs with tab indentation
+ tabsPrinter *Printer
+}
+
+func (p *Printer) reset() {
+ p.wantSpace = spaceWritten
+ p.wantNewline, p.mustNewline = false, false
+ p.pendingComments = p.pendingComments[:0]
+
+ // minification uses its own newline logic
+ p.firstLine = !p.minify
+ p.line = 0
+
+ p.lastLevel, p.level = 0, 0
+ p.levelIncs = p.levelIncs[:0]
+ p.nestedBinary = false
+ p.pendingHdocs = p.pendingHdocs[:0]
+}
+
+func (p *Printer) spaces(n uint) {
+ for i := uint(0); i < n; i++ {
+ p.WriteByte(' ')
+ }
+}
+
+func (p *Printer) space() {
+ p.WriteByte(' ')
+ p.wantSpace = spaceWritten
+}
+
+func (p *Printer) spacePad(pos Pos) {
+ if p.cols.lineStart && p.indentSpaces == 0 {
+ // Never add padding at the start of a line unless we are indenting
+ // with spaces, since this may result in mixing of spaces and tabs.
+ return
+ }
+ if p.wantSpace == spaceRequired {
+ p.WriteByte(' ')
+ p.wantSpace = spaceWritten
+ }
+ for p.cols.column > 0 && p.cols.column < int(pos.Col()) {
+ p.WriteByte(' ')
+ }
+}
+
+// wantsNewline reports whether we want to print at least one newline before
+// printing a node at a given position. A zero position can be given to simply
+// tell if we want a newline following what's just been printed.
+func (p *Printer) wantsNewline(pos Pos) bool {
+ if p.mustNewline {
+ // We must have a newline here.
+ return true
+ }
+ if p.singleLine && len(p.pendingComments) == 0 {
+ // The newline is optional, and singleLine skips it.
+ // Don't skip if there are any pending comments,
+ // as that might move them further down to the wrong place.
+ return false
+ }
+ // THe newline is optional, and we want it via either wantNewline or via
+ // the position's line.
+ return p.wantNewline || pos.Line() > p.line
+}
+
+func (p *Printer) bslashNewl() {
+ if p.wantSpace == spaceRequired {
+ p.space()
+ }
+ p.WriteString("\\\n")
+ p.line++
+ p.indent()
+}
+
+func (p *Printer) spacedString(s string, pos Pos) {
+ p.spacePad(pos)
+ p.WriteString(s)
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) spacedToken(s string, pos Pos) {
+ if p.minify {
+ p.WriteString(s)
+ p.wantSpace = spaceNotRequired
+ return
+ }
+ p.spacePad(pos)
+ p.WriteString(s)
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) semiOrNewl(s string, pos Pos) {
+ if p.wantsNewline(Pos{}) {
+ p.newline(pos)
+ p.indent()
+ } else {
+ if !p.wroteSemi {
+ p.WriteByte(';')
+ }
+ if !p.minify {
+ p.space()
+ }
+ p.advanceLine(pos.Line())
+ }
+ p.WriteString(s)
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) writeLit(s string) {
+ // If p.tabWriter is nil, this is the nested printer being used to print
+ // <<- heredoc bodies, so the parent printer will add the escape bytes
+ // later.
+ if p.tabWriter != nil && strings.Contains(s, "\t") {
+ p.WriteByte(tabwriter.Escape)
+ defer p.WriteByte(tabwriter.Escape)
+ }
+ p.WriteString(s)
+}
+
+func (p *Printer) incLevel() {
+ inc := false
+ if p.level <= p.lastLevel || len(p.levelIncs) == 0 {
+ p.level++
+ inc = true
+ } else if last := &p.levelIncs[len(p.levelIncs)-1]; *last {
+ *last = false
+ inc = true
+ }
+ p.levelIncs = append(p.levelIncs, inc)
+}
+
+func (p *Printer) decLevel() {
+ if p.levelIncs[len(p.levelIncs)-1] {
+ p.level--
+ }
+ p.levelIncs = p.levelIncs[:len(p.levelIncs)-1]
+}
+
+func (p *Printer) indent() {
+ if p.minify {
+ return
+ }
+ p.lastLevel = p.level
+ switch {
+ case p.level == 0:
+ case p.indentSpaces == 0:
+ p.WriteByte(tabwriter.Escape)
+ for i := uint(0); i < p.level; i++ {
+ p.WriteByte('\t')
+ }
+ p.WriteByte(tabwriter.Escape)
+ default:
+ p.spaces(p.indentSpaces * p.level)
+ }
+}
+
+// TODO(mvdan): add an indent call at the end of newline?
+
+// newline prints one newline and advances p.line to pos.Line().
+func (p *Printer) newline(pos Pos) {
+ p.flushHeredocs()
+ p.flushComments()
+ p.WriteByte('\n')
+ p.wantSpace = spaceWritten
+ p.wantNewline, p.mustNewline = false, false
+ p.advanceLine(pos.Line())
+}
+
+func (p *Printer) advanceLine(line uint) {
+ if p.line < line {
+ p.line = line
+ }
+}
+
+func (p *Printer) flushHeredocs() {
+ if len(p.pendingHdocs) == 0 {
+ return
+ }
+ hdocs := p.pendingHdocs
+ p.pendingHdocs = p.pendingHdocs[:0]
+ coms := p.pendingComments
+ p.pendingComments = nil
+ if len(coms) > 0 {
+ c := coms[0]
+ if c.Pos().Line() == p.line {
+ p.pendingComments = append(p.pendingComments, c)
+ p.flushComments()
+ coms = coms[1:]
+ }
+ }
+
+ // Reuse the last indentation level, as
+ // indentation levels are usually changed before
+ // newlines are printed along with their
+ // subsequent indentation characters.
+ newLevel := p.level
+ p.level = p.lastLevel
+
+ for _, r := range hdocs {
+ p.line++
+ p.WriteByte('\n')
+ p.wantSpace = spaceWritten
+ p.wantNewline, p.wantNewline = false, false
+ if r.Op == DashHdoc && p.indentSpaces == 0 && !p.minify {
+ if r.Hdoc != nil {
+ extra := extraIndenter{
+ bufWriter: p.bufWriter,
+ baseIndent: int(p.level + 1),
+ firstIndent: -1,
+ }
+ p.tabsPrinter = &Printer{
+ bufWriter: &extra,
+
+ // The options need to persist.
+ indentSpaces: p.indentSpaces,
+ binNextLine: p.binNextLine,
+ swtCaseIndent: p.swtCaseIndent,
+ spaceRedirects: p.spaceRedirects,
+ keepPadding: p.keepPadding,
+ minify: p.minify,
+ funcNextLine: p.funcNextLine,
+
+ line: r.Hdoc.Pos().Line(),
+ }
+ p.tabsPrinter.wordParts(r.Hdoc.Parts, true)
+ }
+ p.indent()
+ } else if r.Hdoc != nil {
+ p.wordParts(r.Hdoc.Parts, true)
+ }
+ p.unquotedWord(r.Word)
+ if r.Hdoc != nil {
+ // Overwrite p.line, since printing r.Word again can set
+ // p.line to the beginning of the heredoc again.
+ p.advanceLine(r.Hdoc.End().Line())
+ }
+ p.wantSpace = spaceNotRequired
+ }
+ p.level = newLevel
+ p.pendingComments = coms
+ p.mustNewline = true
+}
+
+// newline prints between zero and two newlines.
+// If any newlines are printed, it advances p.line to pos.Line().
+func (p *Printer) newlines(pos Pos) {
+ if p.firstLine && len(p.pendingComments) == 0 {
+ p.firstLine = false
+ return // no empty lines at the top
+ }
+ if !p.wantsNewline(pos) {
+ return
+ }
+ p.flushHeredocs()
+ p.flushComments()
+ p.WriteByte('\n')
+ p.wantSpace = spaceWritten
+ p.wantNewline, p.mustNewline = false, false
+
+ l := pos.Line()
+ if l > p.line+1 && !p.minify {
+ p.WriteByte('\n') // preserve single empty lines
+ }
+ p.advanceLine(l)
+ p.indent()
+}
+
+func (p *Printer) rightParen(pos Pos) {
+ if !p.minify {
+ p.newlines(pos)
+ }
+ p.WriteByte(')')
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) semiRsrv(s string, pos Pos) {
+ if p.wantsNewline(pos) {
+ p.newlines(pos)
+ } else {
+ if !p.wroteSemi {
+ p.WriteByte(';')
+ }
+ if !p.minify {
+ p.spacePad(pos)
+ }
+ }
+ p.WriteString(s)
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) flushComments() {
+ for i, c := range p.pendingComments {
+ if i == 0 {
+ // Flush any pending heredocs first. Otherwise, the
+ // comments would become part of a heredoc body.
+ p.flushHeredocs()
+ }
+ p.firstLine = false
+ // We can't call any of the newline methods, as they call this
+ // function and we'd recurse forever.
+ cline := c.Hash.Line()
+ switch {
+ case p.mustNewline, i > 0, cline > p.line && p.line > 0:
+ p.WriteByte('\n')
+ if cline > p.line+1 {
+ p.WriteByte('\n')
+ }
+ p.indent()
+ p.wantSpace = spaceWritten
+ p.spacePad(c.Pos())
+ case p.wantSpace == spaceRequired:
+ if p.keepPadding {
+ p.spacePad(c.Pos())
+ } else {
+ p.WriteByte('\t')
+ }
+ case p.wantSpace != spaceWritten:
+ p.space()
+ }
+ // don't go back one line, which may happen in some edge cases
+ p.advanceLine(cline)
+ p.WriteByte('#')
+ p.writeLit(strings.TrimRightFunc(c.Text, unicode.IsSpace))
+ p.wantNewline = true
+ p.mustNewline = true
+ }
+ p.pendingComments = nil
+}
+
+func (p *Printer) comments(comments ...Comment) {
+ if p.minify {
+ for _, c := range comments {
+ if fileutil.Shebang([]byte("#"+c.Text)) != "" && c.Hash.Col() == 1 && c.Hash.Line() == 1 {
+ p.WriteString(strings.TrimRightFunc("#"+c.Text, unicode.IsSpace))
+ p.WriteString("\n")
+ p.line++
+ }
+ }
+ return
+ }
+ p.pendingComments = append(p.pendingComments, comments...)
+}
+
+func (p *Printer) wordParts(wps []WordPart, quoted bool) {
+ // We disallow unquoted escaped newlines between word parts below.
+ // However, we want to allow a leading escaped newline for cases such as:
+ //
+ // foo <<< \
+ // "bar baz"
+ if !quoted && !p.singleLine && wps[0].Pos().Line() > p.line {
+ p.bslashNewl()
+ }
+ for i, wp := range wps {
+ var next WordPart
+ if i+1 < len(wps) {
+ next = wps[i+1]
+ }
+ // Keep escaped newlines separating word parts when quoted.
+ // Note that those escaped newlines don't cause indentaiton.
+ // When not quoted, we strip them out consistently,
+ // because attempting to keep them would prevent indentation.
+ // Can't use p.wantsNewline here, since this is only about
+ // escaped newlines.
+ for quoted && !p.singleLine && wp.Pos().Line() > p.line {
+ p.WriteString("\\\n")
+ p.line++
+ }
+ p.wordPart(wp, next)
+ p.advanceLine(wp.End().Line())
+ }
+}
+
+func (p *Printer) wordPart(wp, next WordPart) {
+ switch x := wp.(type) {
+ case *Lit:
+ p.writeLit(x.Value)
+ case *SglQuoted:
+ if x.Dollar {
+ p.WriteByte('$')
+ }
+ p.WriteByte('\'')
+ p.writeLit(x.Value)
+ p.WriteByte('\'')
+ p.advanceLine(x.End().Line())
+ case *DblQuoted:
+ p.dblQuoted(x)
+ case *CmdSubst:
+ p.advanceLine(x.Pos().Line())
+ switch {
+ case x.TempFile:
+ p.WriteString("${")
+ p.wantSpace = spaceRequired
+ p.nestedStmts(x.Stmts, x.Last, x.Right)
+ p.wantSpace = spaceNotRequired
+ p.semiRsrv("}", x.Right)
+ case x.ReplyVar:
+ p.WriteString("${|")
+ p.nestedStmts(x.Stmts, x.Last, x.Right)
+ p.wantSpace = spaceNotRequired
+ p.semiRsrv("}", x.Right)
+ // Special case: `# inline comment`
+ case x.Backquotes && len(x.Stmts) == 0 &&
+ len(x.Last) == 1 && x.Right.Line() == p.line:
+ p.WriteString("`#")
+ p.WriteString(x.Last[0].Text)
+ p.WriteString("`")
+ default:
+ p.WriteString("$(")
+ if len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0]) {
+ p.wantSpace = spaceRequired
+ } else {
+ p.wantSpace = spaceNotRequired
+ }
+ p.nestedStmts(x.Stmts, x.Last, x.Right)
+ p.rightParen(x.Right)
+ }
+ case *ParamExp:
+ litCont := ";"
+ if nextLit, ok := next.(*Lit); ok && nextLit.Value != "" {
+ litCont = nextLit.Value[:1]
+ }
+ name := x.Param.Value
+ switch {
+ case !p.minify:
+ case x.Excl, x.Length, x.Width:
+ case x.Index != nil, x.Slice != nil:
+ case x.Repl != nil, x.Exp != nil:
+ case len(name) > 1 && !ValidName(name): // ${10}
+ case ValidName(name + litCont): // ${var}cont
+ default:
+ x2 := *x
+ x2.Short = true
+ p.paramExp(&x2)
+ return
+ }
+ p.paramExp(x)
+ case *ArithmExp:
+ p.WriteString("$((")
+ if x.Unsigned {
+ p.WriteString("# ")
+ }
+ p.arithmExpr(x.X, false, false)
+ p.WriteString("))")
+ case *ExtGlob:
+ p.WriteString(x.Op.String())
+ p.writeLit(x.Pattern.Value)
+ p.WriteByte(')')
+ case *ProcSubst:
+ // avoid conflict with << and others
+ if p.wantSpace == spaceRequired {
+ p.space()
+ }
+ p.WriteString(x.Op.String())
+ p.nestedStmts(x.Stmts, x.Last, x.Rparen)
+ p.rightParen(x.Rparen)
+ }
+}
+
+func (p *Printer) dblQuoted(dq *DblQuoted) {
+ if dq.Dollar {
+ p.WriteByte('$')
+ }
+ p.WriteByte('"')
+ if len(dq.Parts) > 0 {
+ p.wordParts(dq.Parts, true)
+ }
+ // Add any trailing escaped newlines.
+ for p.line < dq.Right.Line() {
+ p.WriteString("\\\n")
+ p.line++
+ }
+ p.WriteByte('"')
+}
+
+func (p *Printer) wroteIndex(index ArithmExpr) bool {
+ if index == nil {
+ return false
+ }
+ p.WriteByte('[')
+ p.arithmExpr(index, false, false)
+ p.WriteByte(']')
+ return true
+}
+
+func (p *Printer) paramExp(pe *ParamExp) {
+ if pe.nakedIndex() { // arr[x]
+ p.writeLit(pe.Param.Value)
+ p.wroteIndex(pe.Index)
+ return
+ }
+ if pe.Short { // $var
+ p.WriteByte('$')
+ p.writeLit(pe.Param.Value)
+ return
+ }
+ // ${var...}
+ p.WriteString("${")
+ switch {
+ case pe.Length:
+ p.WriteByte('#')
+ case pe.Width:
+ p.WriteByte('%')
+ case pe.Excl:
+ p.WriteByte('!')
+ }
+ p.writeLit(pe.Param.Value)
+ p.wroteIndex(pe.Index)
+ switch {
+ case pe.Slice != nil:
+ p.WriteByte(':')
+ p.arithmExpr(pe.Slice.Offset, true, true)
+ if pe.Slice.Length != nil {
+ p.WriteByte(':')
+ p.arithmExpr(pe.Slice.Length, true, false)
+ }
+ case pe.Repl != nil:
+ if pe.Repl.All {
+ p.WriteByte('/')
+ }
+ p.WriteByte('/')
+ if pe.Repl.Orig != nil {
+ p.word(pe.Repl.Orig)
+ }
+ p.WriteByte('/')
+ if pe.Repl.With != nil {
+ p.word(pe.Repl.With)
+ }
+ case pe.Names != 0:
+ p.writeLit(pe.Names.String())
+ case pe.Exp != nil:
+ p.WriteString(pe.Exp.Op.String())
+ if pe.Exp.Word != nil {
+ p.word(pe.Exp.Word)
+ }
+ }
+ p.WriteByte('}')
+}
+
+func (p *Printer) loop(loop Loop) {
+ switch x := loop.(type) {
+ case *WordIter:
+ p.writeLit(x.Name.Value)
+ if x.InPos.IsValid() {
+ p.spacedString(" in", Pos{})
+ p.wordJoin(x.Items)
+ }
+ case *CStyleLoop:
+ p.WriteString("((")
+ if x.Init == nil {
+ p.space()
+ }
+ p.arithmExpr(x.Init, false, false)
+ p.WriteString("; ")
+ p.arithmExpr(x.Cond, false, false)
+ p.WriteString("; ")
+ p.arithmExpr(x.Post, false, false)
+ p.WriteString("))")
+ }
+}
+
+func (p *Printer) arithmExpr(expr ArithmExpr, compact, spacePlusMinus bool) {
+ if p.minify {
+ compact = true
+ }
+ switch x := expr.(type) {
+ case *Word:
+ p.word(x)
+ case *BinaryArithm:
+ if compact {
+ p.arithmExpr(x.X, compact, spacePlusMinus)
+ p.WriteString(x.Op.String())
+ p.arithmExpr(x.Y, compact, false)
+ } else {
+ p.arithmExpr(x.X, compact, spacePlusMinus)
+ if x.Op != Comma {
+ p.space()
+ }
+ p.WriteString(x.Op.String())
+ p.space()
+ p.arithmExpr(x.Y, compact, false)
+ }
+ case *UnaryArithm:
+ if x.Post {
+ p.arithmExpr(x.X, compact, spacePlusMinus)
+ p.WriteString(x.Op.String())
+ } else {
+ if spacePlusMinus {
+ switch x.Op {
+ case Plus, Minus:
+ p.space()
+ }
+ }
+ p.WriteString(x.Op.String())
+ p.arithmExpr(x.X, compact, false)
+ }
+ case *ParenArithm:
+ p.WriteByte('(')
+ p.arithmExpr(x.X, false, false)
+ p.WriteByte(')')
+ }
+}
+
+func (p *Printer) testExpr(expr TestExpr) {
+ // Multi-line test expressions don't need to escape newlines.
+ if expr.Pos().Line() > p.line {
+ p.newlines(expr.Pos())
+ p.spacePad(expr.Pos())
+ } else if p.wantSpace == spaceRequired {
+ p.space()
+ }
+ p.testExprSameLine(expr)
+}
+
+func (p *Printer) testExprSameLine(expr TestExpr) {
+ p.advanceLine(expr.Pos().Line())
+ switch x := expr.(type) {
+ case *Word:
+ p.word(x)
+ case *BinaryTest:
+ p.testExprSameLine(x.X)
+ p.space()
+ p.WriteString(x.Op.String())
+ switch x.Op {
+ case AndTest, OrTest:
+ p.wantSpace = spaceRequired
+ p.testExpr(x.Y)
+ default:
+ p.space()
+ p.testExprSameLine(x.Y)
+ }
+ case *UnaryTest:
+ p.WriteString(x.Op.String())
+ p.space()
+ p.testExprSameLine(x.X)
+ case *ParenTest:
+ p.WriteByte('(')
+ if startsWithLparen(x.X) {
+ p.wantSpace = spaceRequired
+ } else {
+ p.wantSpace = spaceNotRequired
+ }
+ p.testExpr(x.X)
+ p.WriteByte(')')
+ }
+}
+
+func (p *Printer) word(w *Word) {
+ p.wordParts(w.Parts, false)
+ p.wantSpace = spaceRequired
+}
+
+func (p *Printer) unquotedWord(w *Word) {
+ for _, wp := range w.Parts {
+ switch x := wp.(type) {
+ case *SglQuoted:
+ p.writeLit(x.Value)
+ case *DblQuoted:
+ p.wordParts(x.Parts, true)
+ case *Lit:
+ for i := 0; i < len(x.Value); i++ {
+ if b := x.Value[i]; b == '\\' {
+ if i++; i < len(x.Value) {
+ p.WriteByte(x.Value[i])
+ }
+ } else {
+ p.WriteByte(b)
+ }
+ }
+ }
+ }
+}
+
+func (p *Printer) wordJoin(ws []*Word) {
+ anyNewline := false
+ for _, w := range ws {
+ if pos := w.Pos(); pos.Line() > p.line && !p.singleLine {
+ if !anyNewline {
+ p.incLevel()
+ anyNewline = true
+ }
+ p.bslashNewl()
+ }
+ p.spacePad(w.Pos())
+ p.word(w)
+ }
+ if anyNewline {
+ p.decLevel()
+ }
+}
+
+func (p *Printer) casePatternJoin(pats []*Word) {
+ anyNewline := false
+ for i, w := range pats {
+ if i > 0 {
+ p.spacedToken("|", Pos{})
+ }
+ if p.wantsNewline(w.Pos()) {
+ if !anyNewline {
+ p.incLevel()
+ anyNewline = true
+ }
+ p.bslashNewl()
+ } else {
+ p.spacePad(w.Pos())
+ }
+ p.word(w)
+ }
+ if anyNewline {
+ p.decLevel()
+ }
+}
+
+func (p *Printer) elemJoin(elems []*ArrayElem, last []Comment) {
+ p.incLevel()
+ for _, el := range elems {
+ var left []Comment
+ for _, c := range el.Comments {
+ if c.Pos().After(el.Pos()) {
+ left = append(left, c)
+ break
+ }
+ p.comments(c)
+ }
+ // Multi-line array expressions don't need to escape newlines.
+ if el.Pos().Line() > p.line {
+ p.newlines(el.Pos())
+ p.spacePad(el.Pos())
+ } else if p.wantSpace == spaceRequired {
+ p.space()
+ }
+ if p.wroteIndex(el.Index) {
+ p.WriteByte('=')
+ }
+ if el.Value != nil {
+ p.word(el.Value)
+ }
+ p.comments(left...)
+ }
+ if len(last) > 0 {
+ p.comments(last...)
+ p.flushComments()
+ }
+ p.decLevel()
+}
+
+func (p *Printer) stmt(s *Stmt) {
+ p.wroteSemi = false
+ if s.Negated {
+ p.spacedString("!", s.Pos())
+ }
+ var startRedirs int
+ if s.Cmd != nil {
+ startRedirs = p.command(s.Cmd, s.Redirs)
+ }
+ p.incLevel()
+ for _, r := range s.Redirs[startRedirs:] {
+ if p.wantsNewline(r.OpPos) {
+ p.bslashNewl()
+ }
+ if p.wantSpace == spaceRequired {
+ p.spacePad(r.Pos())
+ }
+ if r.N != nil {
+ p.writeLit(r.N.Value)
+ }
+ p.WriteString(r.Op.String())
+ if p.spaceRedirects && (r.Op != DplIn && r.Op != DplOut) {
+ p.space()
+ } else {
+ p.wantSpace = spaceRequired
+ }
+ p.word(r.Word)
+ if r.Op == Hdoc || r.Op == DashHdoc {
+ p.pendingHdocs = append(p.pendingHdocs, r)
+ }
+ }
+ sep := s.Semicolon.IsValid() && s.Semicolon.Line() > p.line && !p.singleLine
+ if sep || s.Background || s.Coprocess {
+ if sep {
+ p.bslashNewl()
+ } else if !p.minify {
+ p.space()
+ }
+ if s.Background {
+ p.WriteString("&")
+ } else if s.Coprocess {
+ p.WriteString("|&")
+ } else {
+ p.WriteString(";")
+ }
+ p.wroteSemi = true
+ p.wantSpace = spaceRequired
+ }
+ p.decLevel()
+}
+
+func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
+ p.advanceLine(cmd.Pos().Line())
+ p.spacePad(cmd.Pos())
+ switch x := cmd.(type) {
+ case *CallExpr:
+ p.assigns(x.Assigns)
+ if len(x.Args) <= 1 {
+ p.wordJoin(x.Args)
+ return 0
+ }
+ p.wordJoin(x.Args[:1])
+ for _, r := range redirs {
+ if r.Pos().After(x.Args[1].Pos()) || r.Op == Hdoc || r.Op == DashHdoc {
+ break
+ }
+ if p.wantSpace == spaceRequired {
+ p.spacePad(r.Pos())
+ }
+ if r.N != nil {
+ p.writeLit(r.N.Value)
+ }
+ p.WriteString(r.Op.String())
+ if p.spaceRedirects && (r.Op != DplIn && r.Op != DplOut) {
+ p.space()
+ } else {
+ p.wantSpace = spaceRequired
+ }
+ p.word(r.Word)
+ startRedirs++
+ }
+ p.wordJoin(x.Args[1:])
+ case *Block:
+ p.WriteByte('{')
+ p.wantSpace = spaceRequired
+ // Forbid "foo()\n{ bar; }"
+ p.wantNewline = p.wantNewline || p.funcNextLine
+ p.nestedStmts(x.Stmts, x.Last, x.Rbrace)
+ p.semiRsrv("}", x.Rbrace)
+ case *IfClause:
+ p.ifClause(x, false)
+ case *Subshell:
+ p.WriteByte('(')
+ stmts := x.Stmts
+ if len(stmts) > 0 && startsWithLparen(stmts[0]) {
+ p.wantSpace = spaceRequired
+ // Add a space between nested parentheses if we're printing them in a single line,
+ // to avoid the ambiguity between `((` and `( (`.
+ if (x.Lparen.Line() != stmts[0].Pos().Line() || len(stmts) > 1) && !p.singleLine {
+ p.wantSpace = spaceNotRequired
+
+ if p.minify {
+ p.mustNewline = true
+ }
+ }
+ } else {
+ p.wantSpace = spaceNotRequired
+ }
+
+ p.spacePad(stmtsPos(x.Stmts, x.Last))
+ p.nestedStmts(x.Stmts, x.Last, x.Rparen)
+ p.wantSpace = spaceNotRequired
+ p.spacePad(x.Rparen)
+ p.rightParen(x.Rparen)
+ case *WhileClause:
+ if x.Until {
+ p.spacedString("until", x.Pos())
+ } else {
+ p.spacedString("while", x.Pos())
+ }
+ p.nestedStmts(x.Cond, x.CondLast, Pos{})
+ p.semiOrNewl("do", x.DoPos)
+ p.nestedStmts(x.Do, x.DoLast, x.DonePos)
+ p.semiRsrv("done", x.DonePos)
+ case *ForClause:
+ if x.Select {
+ p.WriteString("select ")
+ } else {
+ p.WriteString("for ")
+ }
+ p.loop(x.Loop)
+ p.semiOrNewl("do", x.DoPos)
+ p.nestedStmts(x.Do, x.DoLast, x.DonePos)
+ p.semiRsrv("done", x.DonePos)
+ case *BinaryCmd:
+ p.stmt(x.X)
+ if p.minify || p.singleLine || x.Y.Pos().Line() <= p.line {
+ // leave p.nestedBinary untouched
+ p.spacedToken(x.Op.String(), x.OpPos)
+ p.advanceLine(x.Y.Pos().Line())
+ p.stmt(x.Y)
+ break
+ }
+ indent := !p.nestedBinary
+ if indent {
+ p.incLevel()
+ }
+ if p.binNextLine {
+ if len(p.pendingHdocs) == 0 {
+ p.bslashNewl()
+ }
+ p.spacedToken(x.Op.String(), x.OpPos)
+ if len(x.Y.Comments) > 0 {
+ p.wantSpace = spaceNotRequired
+ p.newline(x.Y.Pos())
+ p.indent()
+ p.comments(x.Y.Comments...)
+ p.newline(Pos{})
+ p.indent()
+ }
+ } else {
+ p.spacedToken(x.Op.String(), x.OpPos)
+ p.advanceLine(x.OpPos.Line())
+ p.comments(x.Y.Comments...)
+ p.newline(Pos{})
+ p.indent()
+ }
+ p.advanceLine(x.Y.Pos().Line())
+ _, p.nestedBinary = x.Y.Cmd.(*BinaryCmd)
+ p.stmt(x.Y)
+ if indent {
+ p.decLevel()
+ }
+ p.nestedBinary = false
+ case *FuncDecl:
+ if x.RsrvWord {
+ p.WriteString("function ")
+ }
+ p.writeLit(x.Name.Value)
+ if !x.RsrvWord || x.Parens {
+ p.WriteString("()")
+ }
+ if p.funcNextLine {
+ p.newline(Pos{})
+ p.indent()
+ } else if !x.Parens || !p.minify {
+ p.space()
+ }
+ p.advanceLine(x.Body.Pos().Line())
+ p.comments(x.Body.Comments...)
+ p.stmt(x.Body)
+ case *CaseClause:
+ p.WriteString("case ")
+ p.word(x.Word)
+ p.WriteString(" in")
+ p.advanceLine(x.In.Line())
+ p.wantSpace = spaceRequired
+ if p.swtCaseIndent {
+ p.incLevel()
+ }
+ if len(x.Items) == 0 {
+ // Apparently "case x in; esac" is invalid shell.
+ p.mustNewline = true
+ }
+ for i, ci := range x.Items {
+ var last []Comment
+ for i, c := range ci.Comments {
+ if c.Pos().After(ci.Pos()) {
+ last = ci.Comments[i:]
+ break
+ }
+ p.comments(c)
+ }
+ p.newlines(ci.Pos())
+ p.spacePad(ci.Pos())
+ p.casePatternJoin(ci.Patterns)
+ p.WriteByte(')')
+ if !p.minify {
+ p.wantSpace = spaceRequired
+ } else {
+ p.wantSpace = spaceNotRequired
+ }
+
+ bodyPos := stmtsPos(ci.Stmts, ci.Last)
+ bodyEnd := stmtsEnd(ci.Stmts, ci.Last)
+ sep := len(ci.Stmts) > 1 || bodyPos.Line() > p.line ||
+ (bodyEnd.IsValid() && ci.OpPos.Line() > bodyEnd.Line())
+ p.nestedStmts(ci.Stmts, ci.Last, ci.OpPos)
+ p.level++
+ if !p.minify || i != len(x.Items)-1 {
+ if sep {
+ p.newlines(ci.OpPos)
+ p.wantNewline = true
+ }
+ p.spacedToken(ci.Op.String(), ci.OpPos)
+ p.advanceLine(ci.OpPos.Line())
+ // avoid ; directly after tokens like ;;
+ p.wroteSemi = true
+ }
+ p.comments(last...)
+ p.flushComments()
+ p.level--
+ }
+ p.comments(x.Last...)
+ if p.swtCaseIndent {
+ p.flushComments()
+ p.decLevel()
+ }
+ p.semiRsrv("esac", x.Esac)
+ case *ArithmCmd:
+ p.WriteString("((")
+ if x.Unsigned {
+ p.WriteString("# ")
+ }
+ p.arithmExpr(x.X, false, false)
+ p.WriteString("))")
+ case *TestClause:
+ p.WriteString("[[ ")
+ p.incLevel()
+ p.testExpr(x.X)
+ p.decLevel()
+ p.spacedString("]]", x.Right)
+ case *DeclClause:
+ p.spacedString(x.Variant.Value, x.Pos())
+ p.assigns(x.Args)
+ case *TimeClause:
+ p.spacedString("time", x.Pos())
+ if x.PosixFormat {
+ p.spacedString("-p", x.Pos())
+ }
+ if x.Stmt != nil {
+ p.stmt(x.Stmt)
+ }
+ case *CoprocClause:
+ p.spacedString("coproc", x.Pos())
+ if x.Name != nil {
+ p.space()
+ p.word(x.Name)
+ }
+ p.space()
+ p.stmt(x.Stmt)
+ case *LetClause:
+ p.spacedString("let", x.Pos())
+ for _, n := range x.Exprs {
+ p.space()
+ p.arithmExpr(n, true, false)
+ }
+ case *TestDecl:
+ p.spacedString("@test", x.Pos())
+ p.space()
+ p.word(x.Description)
+ p.space()
+ p.stmt(x.Body)
+ default:
+ panic(fmt.Sprintf("syntax.Printer: unexpected node type %T", x))
+ }
+ return startRedirs
+}
+
+func (p *Printer) ifClause(ic *IfClause, elif bool) {
+ if !elif {
+ p.spacedString("if", ic.Pos())
+ }
+ p.nestedStmts(ic.Cond, ic.CondLast, Pos{})
+ p.semiOrNewl("then", ic.ThenPos)
+ thenEnd := ic.FiPos
+ el := ic.Else
+ if el != nil {
+ thenEnd = el.Position
+ }
+ p.nestedStmts(ic.Then, ic.ThenLast, thenEnd)
+
+ if el != nil && el.ThenPos.IsValid() {
+ p.comments(ic.Last...)
+ p.semiRsrv("elif", el.Position)
+ p.ifClause(el, true)
+ return
+ }
+ if el == nil {
+ p.comments(ic.Last...)
+ } else {
+ var left []Comment
+ for _, c := range ic.Last {
+ if c.Pos().After(el.Position) {
+ left = append(left, c)
+ break
+ }
+ p.comments(c)
+ }
+ p.semiRsrv("else", el.Position)
+ p.comments(left...)
+ p.nestedStmts(el.Then, el.ThenLast, ic.FiPos)
+ p.comments(el.Last...)
+ }
+ p.semiRsrv("fi", ic.FiPos)
+}
+
+func (p *Printer) stmtList(stmts []*Stmt, last []Comment) {
+ sep := p.wantNewline || (len(stmts) > 0 && stmts[0].Pos().Line() > p.line)
+ for i, s := range stmts {
+ if i > 0 && p.singleLine && p.wantNewline && !p.wroteSemi {
+ // In singleLine mode, ensure we use semicolons between
+ // statements.
+ p.WriteByte(';')
+ p.wantSpace = spaceRequired
+ }
+ pos := s.Pos()
+ var midComs, endComs []Comment
+ for _, c := range s.Comments {
+ // Comments after the end of this command. Note that
+ // this includes "< 1:
+ // Force a newline if we find:
+ // { stmt; stmt; }
+ p.wantNewline = true
+ case closing.Line() > p.line && len(stmts) > 0 &&
+ stmtsEnd(stmts, last).Line() < closing.Line():
+ // Force a newline if we find:
+ // { stmt
+ // }
+ p.wantNewline = true
+ case len(p.pendingComments) > 0 && len(stmts) > 0:
+ // Force a newline if we find:
+ // for i in a b # stmt
+ // do foo; done
+ p.wantNewline = true
+ }
+ p.stmtList(stmts, last)
+ if closing.IsValid() {
+ p.flushComments()
+ }
+ p.decLevel()
+}
+
+func (p *Printer) assigns(assigns []*Assign) {
+ p.incLevel()
+ for _, a := range assigns {
+ if p.wantsNewline(a.Pos()) {
+ p.bslashNewl()
+ } else {
+ p.spacePad(a.Pos())
+ }
+ if a.Name != nil {
+ p.writeLit(a.Name.Value)
+ p.wroteIndex(a.Index)
+ if a.Append {
+ p.WriteByte('+')
+ }
+ if !a.Naked {
+ p.WriteByte('=')
+ }
+ }
+ if a.Value != nil {
+ // Ensure we don't use an escaped newline after '=',
+ // because that can result in indentation, thus
+ // splitting "foo=bar" into "foo= bar".
+ p.advanceLine(a.Value.Pos().Line())
+ p.word(a.Value)
+ } else if a.Array != nil {
+ p.wantSpace = spaceNotRequired
+ p.WriteByte('(')
+ p.elemJoin(a.Array.Elems, a.Array.Last)
+ p.rightParen(a.Array.Rparen)
+ }
+ p.wantSpace = spaceRequired
+ }
+ p.decLevel()
+}
+
+type wantSpaceState uint8
+
+const (
+ spaceNotRequired wantSpaceState = iota
+ spaceRequired // we should generally print a space or a newline next
+ spaceWritten // we have just written a space or newline
+)
+
+// extraIndenter ensures that all lines in a '<<-' heredoc body have at least
+// baseIndent leading tabs. Those that had more tab indentation than the first
+// heredoc line will keep that relative indentation.
+type extraIndenter struct {
+ bufWriter
+ baseIndent int
+
+ firstIndent int
+ firstChange int
+ curLine []byte
+}
+
+func (e *extraIndenter) WriteByte(b byte) error {
+ e.curLine = append(e.curLine, b)
+ if b != '\n' {
+ return nil
+ }
+ trimmed := bytes.TrimLeft(e.curLine, "\t")
+ if len(trimmed) == 1 {
+ // no tabs if this is an empty line, i.e. "\n"
+ e.bufWriter.Write(trimmed)
+ e.curLine = e.curLine[:0]
+ return nil
+ }
+
+ lineIndent := len(e.curLine) - len(trimmed)
+ if e.firstIndent < 0 {
+ // This is the first heredoc line we add extra indentation to.
+ // Keep track of how much we indented.
+ e.firstIndent = lineIndent
+ e.firstChange = e.baseIndent - lineIndent
+ lineIndent = e.baseIndent
+
+ } else if lineIndent < e.firstIndent {
+ // This line did not have enough indentation; simply indent it
+ // like the first line.
+ lineIndent = e.firstIndent
+ } else {
+ // This line had plenty of indentation. Add the extra
+ // indentation that the first line had, for consistency.
+ lineIndent += e.firstChange
+ }
+ e.bufWriter.WriteByte(tabwriter.Escape)
+ for i := 0; i < lineIndent; i++ {
+ e.bufWriter.WriteByte('\t')
+ }
+ e.bufWriter.WriteByte(tabwriter.Escape)
+ e.bufWriter.Write(trimmed)
+ e.curLine = e.curLine[:0]
+ return nil
+}
+
+func (e *extraIndenter) WriteString(s string) (int, error) {
+ for i := 0; i < len(s); i++ {
+ e.WriteByte(s[i])
+ }
+ return len(s), nil
+}
+
+func startsWithLparen(node Node) bool {
+ switch node := node.(type) {
+ case *Stmt:
+ return startsWithLparen(node.Cmd)
+ case *BinaryCmd:
+ return startsWithLparen(node.X)
+ case *Subshell:
+ return true // keep ( (
+ case *ArithmCmd:
+ return true // keep ( ((
+ }
+ return false
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/quote.go b/vendor/mvdan.cc/sh/v3/syntax/quote.go
new file mode 100644
index 00000000..6f27eba1
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/quote.go
@@ -0,0 +1,185 @@
+// Copyright (c) 2021, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type QuoteError struct {
+ ByteOffset int
+ Message string
+}
+
+func (e QuoteError) Error() string {
+ return fmt.Sprintf("cannot quote character at byte %d: %s", e.ByteOffset, e.Message)
+}
+
+const (
+ quoteErrNull = "shell strings cannot contain null bytes"
+ quoteErrPOSIX = "POSIX shell lacks escape sequences"
+ quoteErrRange = "rune out of range"
+ quoteErrMksh = "mksh cannot escape codepoints above 16 bits"
+)
+
+// Quote returns a quoted version of the input string,
+// so that the quoted version is expanded or interpreted
+// as the original string in the given language variant.
+//
+// Quoting is necessary when using arbitrary literal strings
+// as words in a shell script or command.
+// Without quoting, one can run into syntax errors,
+// as well as the possibility of running unintended code.
+//
+// An error is returned when a string cannot be quoted for a variant.
+// For instance, POSIX lacks escape sequences for non-printable characters,
+// and no language variant can represent a string containing null bytes.
+// In such cases, the returned error type will be *QuoteError.
+//
+// The quoting strategy is chosen on a best-effort basis,
+// to minimize the amount of extra bytes necessary.
+//
+// Some strings do not require any quoting and are returned unchanged.
+// Those strings can be directly surrounded in single quotes as well.
+func Quote(s string, lang LangVariant) (string, error) {
+ if s == "" {
+ // Special case; an empty string must always be quoted,
+ // as otherwise it expands to zero fields.
+ return "''", nil
+ }
+ shellChars := false
+ nonPrintable := false
+ offs := 0
+ for rem := s; len(rem) > 0; {
+ r, size := utf8.DecodeRuneInString(rem)
+ switch r {
+ // Like regOps; token characters.
+ case ';', '"', '\'', '(', ')', '$', '|', '&', '>', '<', '`',
+ // Whitespace; might result in multiple fields.
+ ' ', '\t', '\r', '\n',
+ // Escape sequences would be expanded.
+ '\\',
+ // Would start a comment unless quoted.
+ '#',
+ // Might result in brace expansion.
+ '{',
+ // Might result in tilde expansion.
+ '~',
+ // Might result in globbing.
+ '*', '?', '[',
+ // Might result in an assignment.
+ '=':
+ shellChars = true
+ case '\x00':
+ return "", &QuoteError{ByteOffset: offs, Message: quoteErrNull}
+ }
+ if r == utf8.RuneError || !unicode.IsPrint(r) {
+ if lang == LangPOSIX {
+ return "", &QuoteError{ByteOffset: offs, Message: quoteErrPOSIX}
+ }
+ nonPrintable = true
+ }
+ rem = rem[size:]
+ offs += size
+ }
+ if !shellChars && !nonPrintable && !IsKeyword(s) {
+ // Nothing to quote; avoid allocating.
+ return s, nil
+ }
+
+ // Single quotes are usually best,
+ // as they don't require any escaping of characters.
+ // If we have any invalid utf8 or non-printable runes,
+ // use $'' so that we can escape them.
+ // Note that we can't use double quotes for those.
+ var b strings.Builder
+ if nonPrintable {
+ b.WriteString("$'")
+ lastRequoteIfHex := false
+ offs := 0
+ for rem := s; len(rem) > 0; {
+ nextRequoteIfHex := false
+ r, size := utf8.DecodeRuneInString(rem)
+ switch {
+ case r == '\'', r == '\\':
+ b.WriteByte('\\')
+ b.WriteRune(r)
+ case unicode.IsPrint(r) && r != utf8.RuneError:
+ if lastRequoteIfHex && isHex(r) {
+ b.WriteString("'$'")
+ }
+ b.WriteRune(r)
+ case r == '\a':
+ b.WriteString(`\a`)
+ case r == '\b':
+ b.WriteString(`\b`)
+ case r == '\f':
+ b.WriteString(`\f`)
+ case r == '\n':
+ b.WriteString(`\n`)
+ case r == '\r':
+ b.WriteString(`\r`)
+ case r == '\t':
+ b.WriteString(`\t`)
+ case r == '\v':
+ b.WriteString(`\v`)
+ case r < utf8.RuneSelf, r == utf8.RuneError && size == 1:
+ // \xXX, fixed at two hexadecimal characters.
+ fmt.Fprintf(&b, "\\x%02x", rem[0])
+ // Unfortunately, mksh allows \x to consume more hex characters.
+ // Ensure that we don't allow it to read more than two.
+ if lang == LangMirBSDKorn {
+ nextRequoteIfHex = true
+ }
+ case r > utf8.MaxRune:
+ // Not a valid Unicode code point?
+ return "", &QuoteError{ByteOffset: offs, Message: quoteErrRange}
+ case lang == LangMirBSDKorn && r > 0xFFFD:
+ // From the CAVEATS section in R59's man page:
+ //
+ // mksh currently uses OPTU-16 internally, which is the same as
+ // UTF-8 and CESU-8 with 0000..FFFD being valid codepoints.
+ return "", &QuoteError{ByteOffset: offs, Message: quoteErrMksh}
+ case r < 0x10000:
+ // \uXXXX, fixed at four hexadecimal characters.
+ fmt.Fprintf(&b, "\\u%04x", r)
+ default:
+ // \UXXXXXXXX, fixed at eight hexadecimal characters.
+ fmt.Fprintf(&b, "\\U%08x", r)
+ }
+ rem = rem[size:]
+ lastRequoteIfHex = nextRequoteIfHex
+ offs += size
+ }
+ b.WriteString("'")
+ return b.String(), nil
+ }
+
+ // Single quotes without any need for escaping.
+ if !strings.Contains(s, "'") {
+ return "'" + s + "'", nil
+ }
+
+ // The string contains single quotes,
+ // so fall back to double quotes.
+ b.WriteByte('"')
+ for _, r := range s {
+ switch r {
+ case '"', '\\', '`', '$':
+ b.WriteByte('\\')
+ }
+ b.WriteRune(r)
+ }
+ b.WriteByte('"')
+ return b.String(), nil
+}
+
+func isHex(r rune) bool {
+ return (r >= '0' && r <= '9') ||
+ (r >= 'a' && r <= 'f') ||
+ (r >= 'A' && r <= 'F')
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/quotestate_string.go b/vendor/mvdan.cc/sh/v3/syntax/quotestate_string.go
new file mode 100644
index 00000000..d43466f8
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/quotestate_string.go
@@ -0,0 +1,61 @@
+// Code generated by "stringer -type=quoteState"; DO NOT EDIT.
+
+package syntax
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[noState-1]
+ _ = x[subCmd-2]
+ _ = x[subCmdBckquo-4]
+ _ = x[dblQuotes-8]
+ _ = x[hdocWord-16]
+ _ = x[hdocBody-32]
+ _ = x[hdocBodyTabs-64]
+ _ = x[arithmExpr-128]
+ _ = x[arithmExprLet-256]
+ _ = x[arithmExprCmd-512]
+ _ = x[arithmExprBrack-1024]
+ _ = x[testExpr-2048]
+ _ = x[testExprRegexp-4096]
+ _ = x[switchCase-8192]
+ _ = x[paramExpName-16384]
+ _ = x[paramExpSlice-32768]
+ _ = x[paramExpRepl-65536]
+ _ = x[paramExpExp-131072]
+ _ = x[arrayElems-262144]
+}
+
+const _quoteState_name = "noStatesubCmdsubCmdBckquodblQuoteshdocWordhdocBodyhdocBodyTabsarithmExprarithmExprLetarithmExprCmdarithmExprBracktestExprtestExprRegexpswitchCaseparamExpNameparamExpSliceparamExpReplparamExpExparrayElems"
+
+var _quoteState_map = map[quoteState]string{
+ 1: _quoteState_name[0:7],
+ 2: _quoteState_name[7:13],
+ 4: _quoteState_name[13:25],
+ 8: _quoteState_name[25:34],
+ 16: _quoteState_name[34:42],
+ 32: _quoteState_name[42:50],
+ 64: _quoteState_name[50:62],
+ 128: _quoteState_name[62:72],
+ 256: _quoteState_name[72:85],
+ 512: _quoteState_name[85:98],
+ 1024: _quoteState_name[98:113],
+ 2048: _quoteState_name[113:121],
+ 4096: _quoteState_name[121:135],
+ 8192: _quoteState_name[135:145],
+ 16384: _quoteState_name[145:157],
+ 32768: _quoteState_name[157:170],
+ 65536: _quoteState_name[170:182],
+ 131072: _quoteState_name[182:193],
+ 262144: _quoteState_name[193:203],
+}
+
+func (i quoteState) String() string {
+ if str, ok := _quoteState_map[i]; ok {
+ return str
+ }
+ return "quoteState(" + strconv.FormatInt(int64(i), 10) + ")"
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/simplify.go b/vendor/mvdan.cc/sh/v3/syntax/simplify.go
new file mode 100644
index 00000000..5a93966e
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/simplify.go
@@ -0,0 +1,255 @@
+// Copyright (c) 2017, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import "bytes"
+
+// Simplify modifies a node to remove redundant pieces of syntax, and returns
+// whether any changes were made.
+//
+// The changes currently applied are:
+//
+// Remove clearly useless parentheses $(( (expr) ))
+// Remove dollars from vars in exprs (($var))
+// Remove duplicate subshells $( (stmts) )
+// Remove redundant quotes [[ "$var" == str ]]
+// Merge negations with unary operators [[ ! -n $var ]]
+// Use single quotes to shorten literals "\$foo"
+// Remove redundant param expansion colons ${foo:-}
+func Simplify(n Node) bool {
+ s := simplifier{}
+ Walk(n, s.visit)
+ return s.modified
+}
+
+type simplifier struct {
+ modified bool
+}
+
+func (s *simplifier) visit(node Node) bool {
+ switch x := node.(type) {
+ case *Assign:
+ x.Index = s.removeParensArithm(x.Index)
+ // Don't inline params, as x[i] and x[$i] mean
+ // different things when x is an associative
+ // array; the first means "i", the second "$i".
+ case *ParamExp:
+ x.Index = s.removeParensArithm(x.Index)
+ // don't inline params - same as above.
+
+ if x.Exp != nil && x.Exp.Op == DefaultUnsetOrNull && x.Exp.Word == nil {
+ s.modified = true
+ x.Exp.Op = DefaultUnset
+ }
+ if x.Slice == nil {
+ break
+ }
+ x.Slice.Offset = s.removeParensArithm(x.Slice.Offset)
+ x.Slice.Offset = s.inlineSimpleParams(x.Slice.Offset)
+ x.Slice.Length = s.removeParensArithm(x.Slice.Length)
+ x.Slice.Length = s.inlineSimpleParams(x.Slice.Length)
+ case *ArithmExp:
+ x.X = s.removeParensArithm(x.X)
+ x.X = s.inlineSimpleParams(x.X)
+ case *ArithmCmd:
+ x.X = s.removeParensArithm(x.X)
+ x.X = s.inlineSimpleParams(x.X)
+ case *ParenArithm:
+ x.X = s.removeParensArithm(x.X)
+ x.X = s.inlineSimpleParams(x.X)
+ case *BinaryArithm:
+ x.X = s.inlineSimpleParams(x.X)
+ x.Y = s.inlineSimpleParams(x.Y)
+ case *CmdSubst:
+ x.Stmts = s.inlineSubshell(x.Stmts)
+ case *Subshell:
+ x.Stmts = s.inlineSubshell(x.Stmts)
+ case *Word:
+ x.Parts = s.simplifyWord(x.Parts)
+ case *TestClause:
+ x.X = s.removeParensTest(x.X)
+ x.X = s.removeNegateTest(x.X)
+ case *ParenTest:
+ x.X = s.removeParensTest(x.X)
+ x.X = s.removeNegateTest(x.X)
+ case *BinaryTest:
+ x.X = s.unquoteParams(x.X)
+ x.X = s.removeNegateTest(x.X)
+ if x.Op == TsMatchShort {
+ s.modified = true
+ x.Op = TsMatch
+ }
+ switch x.Op {
+ case TsMatch, TsNoMatch:
+ // unquoting enables globbing
+ default:
+ x.Y = s.unquoteParams(x.Y)
+ }
+ x.Y = s.removeNegateTest(x.Y)
+ case *UnaryTest:
+ x.X = s.unquoteParams(x.X)
+ }
+ return true
+}
+
+func (s *simplifier) simplifyWord(wps []WordPart) []WordPart {
+parts:
+ for i, wp := range wps {
+ dq, _ := wp.(*DblQuoted)
+ if dq == nil || len(dq.Parts) != 1 {
+ break
+ }
+ lit, _ := dq.Parts[0].(*Lit)
+ if lit == nil {
+ break
+ }
+ var buf bytes.Buffer
+ escaped := false
+ for _, r := range lit.Value {
+ switch r {
+ case '\\':
+ escaped = !escaped
+ if escaped {
+ continue
+ }
+ case '\'':
+ continue parts
+ case '$', '"', '`':
+ escaped = false
+ default:
+ if escaped {
+ continue parts
+ }
+ escaped = false
+ }
+ buf.WriteRune(r)
+ }
+ newVal := buf.String()
+ if newVal == lit.Value {
+ break
+ }
+ s.modified = true
+ wps[i] = &SglQuoted{
+ Left: dq.Pos(),
+ Right: dq.End(),
+ Dollar: dq.Dollar,
+ Value: newVal,
+ }
+ }
+ return wps
+}
+
+func (s *simplifier) removeParensArithm(x ArithmExpr) ArithmExpr {
+ for {
+ par, _ := x.(*ParenArithm)
+ if par == nil {
+ return x
+ }
+ s.modified = true
+ x = par.X
+ }
+}
+
+func (s *simplifier) inlineSimpleParams(x ArithmExpr) ArithmExpr {
+ w, _ := x.(*Word)
+ if w == nil || len(w.Parts) != 1 {
+ return x
+ }
+ pe, _ := w.Parts[0].(*ParamExp)
+ if pe == nil || !ValidName(pe.Param.Value) {
+ // Not a parameter expansion, or not a valid name, like $3.
+ return x
+ }
+ if pe.Excl || pe.Length || pe.Width || pe.Slice != nil ||
+ pe.Repl != nil || pe.Exp != nil || pe.Index != nil {
+ // A complex parameter expansion can't be simplified.
+ //
+ // Note that index expressions can't generally be simplified
+ // either. It's fine to turn ${a[0]} into a[0], but others like
+ // a[*] are invalid in many shells including Bash.
+ return x
+ }
+ s.modified = true
+ return &Word{Parts: []WordPart{pe.Param}}
+}
+
+func (s *simplifier) inlineSubshell(stmts []*Stmt) []*Stmt {
+ for len(stmts) == 1 {
+ st := stmts[0]
+ if st.Negated || st.Background || st.Coprocess ||
+ len(st.Redirs) > 0 {
+ break
+ }
+ sub, _ := st.Cmd.(*Subshell)
+ if sub == nil {
+ break
+ }
+ s.modified = true
+ stmts = sub.Stmts
+ }
+ return stmts
+}
+
+func (s *simplifier) unquoteParams(x TestExpr) TestExpr {
+ w, _ := x.(*Word)
+ if w == nil || len(w.Parts) != 1 {
+ return x
+ }
+ dq, _ := w.Parts[0].(*DblQuoted)
+ if dq == nil || len(dq.Parts) != 1 {
+ return x
+ }
+ if _, ok := dq.Parts[0].(*ParamExp); !ok {
+ return x
+ }
+ s.modified = true
+ w.Parts = dq.Parts
+ return w
+}
+
+func (s *simplifier) removeParensTest(x TestExpr) TestExpr {
+ for {
+ par, _ := x.(*ParenTest)
+ if par == nil {
+ return x
+ }
+ s.modified = true
+ x = par.X
+ }
+}
+
+func (s *simplifier) removeNegateTest(x TestExpr) TestExpr {
+ u, _ := x.(*UnaryTest)
+ if u == nil || u.Op != TsNot {
+ return x
+ }
+ switch y := u.X.(type) {
+ case *UnaryTest:
+ switch y.Op {
+ case TsEmpStr:
+ y.Op = TsNempStr
+ s.modified = true
+ return y
+ case TsNempStr:
+ y.Op = TsEmpStr
+ s.modified = true
+ return y
+ case TsNot:
+ s.modified = true
+ return y.X
+ }
+ case *BinaryTest:
+ switch y.Op {
+ case TsMatch:
+ y.Op = TsNoMatch
+ s.modified = true
+ return y
+ case TsNoMatch:
+ y.Op = TsMatch
+ s.modified = true
+ return y
+ }
+ }
+ return x
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/token_string.go b/vendor/mvdan.cc/sh/v3/syntax/token_string.go
new file mode 100644
index 00000000..ab5c83ac
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/token_string.go
@@ -0,0 +1,149 @@
+// Code generated by "stringer -type token -linecomment -trimprefix _"; DO NOT EDIT.
+
+package syntax
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[illegalTok-0]
+ _ = x[_EOF-1]
+ _ = x[_Newl-2]
+ _ = x[_Lit-3]
+ _ = x[_LitWord-4]
+ _ = x[_LitRedir-5]
+ _ = x[sglQuote-6]
+ _ = x[dblQuote-7]
+ _ = x[bckQuote-8]
+ _ = x[and-9]
+ _ = x[andAnd-10]
+ _ = x[orOr-11]
+ _ = x[or-12]
+ _ = x[orAnd-13]
+ _ = x[dollar-14]
+ _ = x[dollSglQuote-15]
+ _ = x[dollDblQuote-16]
+ _ = x[dollBrace-17]
+ _ = x[dollBrack-18]
+ _ = x[dollParen-19]
+ _ = x[dollDblParen-20]
+ _ = x[leftBrack-21]
+ _ = x[dblLeftBrack-22]
+ _ = x[leftParen-23]
+ _ = x[dblLeftParen-24]
+ _ = x[rightBrace-25]
+ _ = x[rightBrack-26]
+ _ = x[rightParen-27]
+ _ = x[dblRightParen-28]
+ _ = x[semicolon-29]
+ _ = x[dblSemicolon-30]
+ _ = x[semiAnd-31]
+ _ = x[dblSemiAnd-32]
+ _ = x[semiOr-33]
+ _ = x[exclMark-34]
+ _ = x[tilde-35]
+ _ = x[addAdd-36]
+ _ = x[subSub-37]
+ _ = x[star-38]
+ _ = x[power-39]
+ _ = x[equal-40]
+ _ = x[nequal-41]
+ _ = x[lequal-42]
+ _ = x[gequal-43]
+ _ = x[addAssgn-44]
+ _ = x[subAssgn-45]
+ _ = x[mulAssgn-46]
+ _ = x[quoAssgn-47]
+ _ = x[remAssgn-48]
+ _ = x[andAssgn-49]
+ _ = x[orAssgn-50]
+ _ = x[xorAssgn-51]
+ _ = x[shlAssgn-52]
+ _ = x[shrAssgn-53]
+ _ = x[rdrOut-54]
+ _ = x[appOut-55]
+ _ = x[rdrIn-56]
+ _ = x[rdrInOut-57]
+ _ = x[dplIn-58]
+ _ = x[dplOut-59]
+ _ = x[clbOut-60]
+ _ = x[hdoc-61]
+ _ = x[dashHdoc-62]
+ _ = x[wordHdoc-63]
+ _ = x[rdrAll-64]
+ _ = x[appAll-65]
+ _ = x[cmdIn-66]
+ _ = x[cmdOut-67]
+ _ = x[plus-68]
+ _ = x[colPlus-69]
+ _ = x[minus-70]
+ _ = x[colMinus-71]
+ _ = x[quest-72]
+ _ = x[colQuest-73]
+ _ = x[assgn-74]
+ _ = x[colAssgn-75]
+ _ = x[perc-76]
+ _ = x[dblPerc-77]
+ _ = x[hash-78]
+ _ = x[dblHash-79]
+ _ = x[caret-80]
+ _ = x[dblCaret-81]
+ _ = x[comma-82]
+ _ = x[dblComma-83]
+ _ = x[at-84]
+ _ = x[slash-85]
+ _ = x[dblSlash-86]
+ _ = x[colon-87]
+ _ = x[tsExists-88]
+ _ = x[tsRegFile-89]
+ _ = x[tsDirect-90]
+ _ = x[tsCharSp-91]
+ _ = x[tsBlckSp-92]
+ _ = x[tsNmPipe-93]
+ _ = x[tsSocket-94]
+ _ = x[tsSmbLink-95]
+ _ = x[tsSticky-96]
+ _ = x[tsGIDSet-97]
+ _ = x[tsUIDSet-98]
+ _ = x[tsGrpOwn-99]
+ _ = x[tsUsrOwn-100]
+ _ = x[tsModif-101]
+ _ = x[tsRead-102]
+ _ = x[tsWrite-103]
+ _ = x[tsExec-104]
+ _ = x[tsNoEmpty-105]
+ _ = x[tsFdTerm-106]
+ _ = x[tsEmpStr-107]
+ _ = x[tsNempStr-108]
+ _ = x[tsOptSet-109]
+ _ = x[tsVarSet-110]
+ _ = x[tsRefVar-111]
+ _ = x[tsReMatch-112]
+ _ = x[tsNewer-113]
+ _ = x[tsOlder-114]
+ _ = x[tsDevIno-115]
+ _ = x[tsEql-116]
+ _ = x[tsNeq-117]
+ _ = x[tsLeq-118]
+ _ = x[tsGeq-119]
+ _ = x[tsLss-120]
+ _ = x[tsGtr-121]
+ _ = x[globQuest-122]
+ _ = x[globStar-123]
+ _ = x[globPlus-124]
+ _ = x[globAt-125]
+ _ = x[globExcl-126]
+}
+
+const _token_name = "illegalTokEOFNewlLitLitWordLitRedir'\"`&&&||||&$$'$\"${$[$($(([[[(((}])));;;;&;;&;|!~++--***==!=<=>=+=-=*=/=%=&=|=^=<<=>>=>>><<><&>&>|<<<<-<<<&>&>><(>(+:+-:-?:?=:=%%%###^^^,,,@///:-e-f-d-c-b-p-S-L-k-g-u-G-O-N-r-w-x-s-t-z-n-o-v-R=~-nt-ot-ef-eq-ne-le-ge-lt-gt?(*(+(@(!("
+
+var _token_index = [...]uint16{0, 10, 13, 17, 20, 27, 35, 36, 37, 38, 39, 41, 43, 44, 46, 47, 49, 51, 53, 55, 57, 60, 61, 63, 64, 66, 67, 68, 69, 71, 72, 74, 76, 79, 81, 82, 83, 85, 87, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 117, 120, 121, 123, 124, 126, 128, 130, 132, 134, 137, 140, 142, 145, 147, 149, 150, 152, 153, 155, 156, 158, 159, 161, 162, 164, 165, 167, 168, 170, 171, 173, 174, 175, 177, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 231, 234, 237, 240, 243, 246, 249, 252, 255, 257, 259, 261, 263, 265}
+
+func (i token) String() string {
+ if i >= token(len(_token_index)-1) {
+ return "token(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _token_name[_token_index[i]:_token_index[i+1]]
+}
diff --git a/vendor/mvdan.cc/sh/v3/syntax/tokens.go b/vendor/mvdan.cc/sh/v3/syntax/tokens.go
new file mode 100644
index 00000000..6a64b213
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/tokens.go
@@ -0,0 +1,349 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+//go:generate stringer -type token -linecomment -trimprefix _
+
+type token uint32
+
+// The list of all possible tokens.
+const (
+ illegalTok token = iota
+
+ _EOF
+ _Newl
+ _Lit
+ _LitWord
+ _LitRedir
+
+ sglQuote // '
+ dblQuote // "
+ bckQuote // `
+
+ and // &
+ andAnd // &&
+ orOr // ||
+ or // |
+ orAnd // |&
+
+ dollar // $
+ dollSglQuote // $'
+ dollDblQuote // $"
+ dollBrace // ${
+ dollBrack // $[
+ dollParen // $(
+ dollDblParen // $((
+ leftBrack // [
+ dblLeftBrack // [[
+ leftParen // (
+ dblLeftParen // ((
+
+ rightBrace // }
+ rightBrack // ]
+ rightParen // )
+ dblRightParen // ))
+ semicolon // ;
+
+ dblSemicolon // ;;
+ semiAnd // ;&
+ dblSemiAnd // ;;&
+ semiOr // ;|
+
+ exclMark // !
+ tilde // ~
+ addAdd // ++
+ subSub // --
+ star // *
+ power // **
+ equal // ==
+ nequal // !=
+ lequal // <=
+ gequal // >=
+
+ addAssgn // +=
+ subAssgn // -=
+ mulAssgn // *=
+ quoAssgn // /=
+ remAssgn // %=
+ andAssgn // &=
+ orAssgn // |=
+ xorAssgn // ^=
+ shlAssgn // <<=
+ shrAssgn // >>=
+
+ rdrOut // >
+ appOut // >>
+ rdrIn // <
+ rdrInOut // <>
+ dplIn // <&
+ dplOut // >&
+ clbOut // >|
+ hdoc // <<
+ dashHdoc // <<-
+ wordHdoc // <<<
+ rdrAll // &>
+ appAll // &>>
+
+ cmdIn // <(
+ cmdOut // >(
+
+ plus // +
+ colPlus // :+
+ minus // -
+ colMinus // :-
+ quest // ?
+ colQuest // :?
+ assgn // =
+ colAssgn // :=
+ perc // %
+ dblPerc // %%
+ hash // #
+ dblHash // ##
+ caret // ^
+ dblCaret // ^^
+ comma // ,
+ dblComma // ,,
+ at // @
+ slash // /
+ dblSlash // //
+ colon // :
+
+ tsExists // -e
+ tsRegFile // -f
+ tsDirect // -d
+ tsCharSp // -c
+ tsBlckSp // -b
+ tsNmPipe // -p
+ tsSocket // -S
+ tsSmbLink // -L
+ tsSticky // -k
+ tsGIDSet // -g
+ tsUIDSet // -u
+ tsGrpOwn // -G
+ tsUsrOwn // -O
+ tsModif // -N
+ tsRead // -r
+ tsWrite // -w
+ tsExec // -x
+ tsNoEmpty // -s
+ tsFdTerm // -t
+ tsEmpStr // -z
+ tsNempStr // -n
+ tsOptSet // -o
+ tsVarSet // -v
+ tsRefVar // -R
+
+ tsReMatch // =~
+ tsNewer // -nt
+ tsOlder // -ot
+ tsDevIno // -ef
+ tsEql // -eq
+ tsNeq // -ne
+ tsLeq // -le
+ tsGeq // -ge
+ tsLss // -lt
+ tsGtr // -gt
+
+ globQuest // ?(
+ globStar // *(
+ globPlus // +(
+ globAt // @(
+ globExcl // !(
+)
+
+type RedirOperator token
+
+const (
+ RdrOut = RedirOperator(rdrOut) + iota // >
+ AppOut // >>
+ RdrIn // <
+ RdrInOut // <>
+ DplIn // <&
+ DplOut // >&
+ ClbOut // >|
+ Hdoc // <<
+ DashHdoc // <<-
+ WordHdoc // <<<
+ RdrAll // &>
+ AppAll // &>>
+)
+
+type ProcOperator token
+
+const (
+ CmdIn = ProcOperator(cmdIn) + iota // <(
+ CmdOut // >(
+)
+
+type GlobOperator token
+
+const (
+ GlobZeroOrOne = GlobOperator(globQuest) + iota // ?(
+ GlobZeroOrMore // *(
+ GlobOneOrMore // +(
+ GlobOne // @(
+ GlobExcept // !(
+)
+
+type BinCmdOperator token
+
+const (
+ AndStmt = BinCmdOperator(andAnd) + iota // &&
+ OrStmt // ||
+ Pipe // |
+ PipeAll // |&
+)
+
+type CaseOperator token
+
+const (
+ Break = CaseOperator(dblSemicolon) + iota // ;;
+ Fallthrough // ;&
+ Resume // ;;&
+ ResumeKorn // ;|
+)
+
+type ParNamesOperator token
+
+const (
+ NamesPrefix = ParNamesOperator(star) // *
+ NamesPrefixWords = ParNamesOperator(at) // @
+)
+
+type ParExpOperator token
+
+const (
+ AlternateUnset = ParExpOperator(plus) + iota // +
+ AlternateUnsetOrNull // :+
+ DefaultUnset // -
+ DefaultUnsetOrNull // :-
+ ErrorUnset // ?
+ ErrorUnsetOrNull // :?
+ AssignUnset // =
+ AssignUnsetOrNull // :=
+ RemSmallSuffix // %
+ RemLargeSuffix // %%
+ RemSmallPrefix // #
+ RemLargePrefix // ##
+ UpperFirst // ^
+ UpperAll // ^^
+ LowerFirst // ,
+ LowerAll // ,,
+ OtherParamOps // @
+)
+
+type UnAritOperator token
+
+const (
+ Not = UnAritOperator(exclMark) + iota // !
+ BitNegation // ~
+ Inc // ++
+ Dec // --
+ Plus = UnAritOperator(plus) // +
+ Minus = UnAritOperator(minus) // -
+)
+
+type BinAritOperator token
+
+const (
+ Add = BinAritOperator(plus) // +
+ Sub = BinAritOperator(minus) // -
+ Mul = BinAritOperator(star) // *
+ Quo = BinAritOperator(slash) // /
+ Rem = BinAritOperator(perc) // %
+ Pow = BinAritOperator(power) // **
+ Eql = BinAritOperator(equal) // ==
+ Gtr = BinAritOperator(rdrOut) // >
+ Lss = BinAritOperator(rdrIn) // <
+ Neq = BinAritOperator(nequal) // !=
+ Leq = BinAritOperator(lequal) // <=
+ Geq = BinAritOperator(gequal) // >=
+ And = BinAritOperator(and) // &
+ Or = BinAritOperator(or) // |
+ Xor = BinAritOperator(caret) // ^
+ Shr = BinAritOperator(appOut) // >>
+ Shl = BinAritOperator(hdoc) // <<
+
+ AndArit = BinAritOperator(andAnd) // &&
+ OrArit = BinAritOperator(orOr) // ||
+ Comma = BinAritOperator(comma) // ,
+ TernQuest = BinAritOperator(quest) // ?
+ TernColon = BinAritOperator(colon) // :
+
+ Assgn = BinAritOperator(assgn) // =
+ AddAssgn = BinAritOperator(addAssgn) // +=
+ SubAssgn = BinAritOperator(subAssgn) // -=
+ MulAssgn = BinAritOperator(mulAssgn) // *=
+ QuoAssgn = BinAritOperator(quoAssgn) // /=
+ RemAssgn = BinAritOperator(remAssgn) // %=
+ AndAssgn = BinAritOperator(andAssgn) // &=
+ OrAssgn = BinAritOperator(orAssgn) // |=
+ XorAssgn = BinAritOperator(xorAssgn) // ^=
+ ShlAssgn = BinAritOperator(shlAssgn) // <<=
+ ShrAssgn = BinAritOperator(shrAssgn) // >>=
+)
+
+type UnTestOperator token
+
+const (
+ TsExists = UnTestOperator(tsExists) + iota // -e
+ TsRegFile // -f
+ TsDirect // -d
+ TsCharSp // -c
+ TsBlckSp // -b
+ TsNmPipe // -p
+ TsSocket // -S
+ TsSmbLink // -L
+ TsSticky // -k
+ TsGIDSet // -g
+ TsUIDSet // -u
+ TsGrpOwn // -G
+ TsUsrOwn // -O
+ TsModif // -N
+ TsRead // -r
+ TsWrite // -w
+ TsExec // -x
+ TsNoEmpty // -s
+ TsFdTerm // -t
+ TsEmpStr // -z
+ TsNempStr // -n
+ TsOptSet // -o
+ TsVarSet // -v
+ TsRefVar // -R
+ TsNot = UnTestOperator(exclMark) // !
+)
+
+type BinTestOperator token
+
+const (
+ TsReMatch = BinTestOperator(tsReMatch) + iota // =~
+ TsNewer // -nt
+ TsOlder // -ot
+ TsDevIno // -ef
+ TsEql // -eq
+ TsNeq // -ne
+ TsLeq // -le
+ TsGeq // -ge
+ TsLss // -lt
+ TsGtr // -gt
+ AndTest = BinTestOperator(andAnd) // &&
+ OrTest = BinTestOperator(orOr) // ||
+ TsMatchShort = BinTestOperator(assgn) // =
+ TsMatch = BinTestOperator(equal) // ==
+ TsNoMatch = BinTestOperator(nequal) // !=
+ TsBefore = BinTestOperator(rdrIn) // <
+ TsAfter = BinTestOperator(rdrOut) // >
+)
+
+func (o RedirOperator) String() string { return token(o).String() }
+func (o ProcOperator) String() string { return token(o).String() }
+func (o GlobOperator) String() string { return token(o).String() }
+func (o BinCmdOperator) String() string { return token(o).String() }
+func (o CaseOperator) String() string { return token(o).String() }
+func (o ParNamesOperator) String() string { return token(o).String() }
+func (o ParExpOperator) String() string { return token(o).String() }
+func (o UnAritOperator) String() string { return token(o).String() }
+func (o BinAritOperator) String() string { return token(o).String() }
+func (o UnTestOperator) String() string { return token(o).String() }
+func (o BinTestOperator) String() string { return token(o).String() }
diff --git a/vendor/mvdan.cc/sh/v3/syntax/walk.go b/vendor/mvdan.cc/sh/v3/syntax/walk.go
new file mode 100644
index 00000000..be3f2090
--- /dev/null
+++ b/vendor/mvdan.cc/sh/v3/syntax/walk.go
@@ -0,0 +1,313 @@
+// Copyright (c) 2016, Daniel Martí
+// See LICENSE for licensing information
+
+package syntax
+
+import (
+ "fmt"
+ "io"
+ "reflect"
+)
+
+func walkStmts(stmts []*Stmt, last []Comment, f func(Node) bool) {
+ for _, s := range stmts {
+ Walk(s, f)
+ }
+ for _, c := range last {
+ Walk(&c, f)
+ }
+}
+
+func walkWords(words []*Word, f func(Node) bool) {
+ for _, w := range words {
+ Walk(w, f)
+ }
+}
+
+// Walk traverses a syntax tree in depth-first order: It starts by calling
+// f(node); node must not be nil. If f returns true, Walk invokes f
+// recursively for each of the non-nil children of node, followed by
+// f(nil).
+func Walk(node Node, f func(Node) bool) {
+ if !f(node) {
+ return
+ }
+
+ switch x := node.(type) {
+ case *File:
+ walkStmts(x.Stmts, x.Last, f)
+ case *Comment:
+ case *Stmt:
+ for _, c := range x.Comments {
+ if !x.End().After(c.Pos()) {
+ defer Walk(&c, f)
+ break
+ }
+ Walk(&c, f)
+ }
+ if x.Cmd != nil {
+ Walk(x.Cmd, f)
+ }
+ for _, r := range x.Redirs {
+ Walk(r, f)
+ }
+ case *Assign:
+ if x.Name != nil {
+ Walk(x.Name, f)
+ }
+ if x.Value != nil {
+ Walk(x.Value, f)
+ }
+ if x.Index != nil {
+ Walk(x.Index, f)
+ }
+ if x.Array != nil {
+ Walk(x.Array, f)
+ }
+ case *Redirect:
+ if x.N != nil {
+ Walk(x.N, f)
+ }
+ Walk(x.Word, f)
+ if x.Hdoc != nil {
+ Walk(x.Hdoc, f)
+ }
+ case *CallExpr:
+ for _, a := range x.Assigns {
+ Walk(a, f)
+ }
+ walkWords(x.Args, f)
+ case *Subshell:
+ walkStmts(x.Stmts, x.Last, f)
+ case *Block:
+ walkStmts(x.Stmts, x.Last, f)
+ case *IfClause:
+ walkStmts(x.Cond, x.CondLast, f)
+ walkStmts(x.Then, x.ThenLast, f)
+ if x.Else != nil {
+ Walk(x.Else, f)
+ }
+ case *WhileClause:
+ walkStmts(x.Cond, x.CondLast, f)
+ walkStmts(x.Do, x.DoLast, f)
+ case *ForClause:
+ Walk(x.Loop, f)
+ walkStmts(x.Do, x.DoLast, f)
+ case *WordIter:
+ Walk(x.Name, f)
+ walkWords(x.Items, f)
+ case *CStyleLoop:
+ if x.Init != nil {
+ Walk(x.Init, f)
+ }
+ if x.Cond != nil {
+ Walk(x.Cond, f)
+ }
+ if x.Post != nil {
+ Walk(x.Post, f)
+ }
+ case *BinaryCmd:
+ Walk(x.X, f)
+ Walk(x.Y, f)
+ case *FuncDecl:
+ Walk(x.Name, f)
+ Walk(x.Body, f)
+ case *Word:
+ for _, wp := range x.Parts {
+ Walk(wp, f)
+ }
+ case *Lit:
+ case *SglQuoted:
+ case *DblQuoted:
+ for _, wp := range x.Parts {
+ Walk(wp, f)
+ }
+ case *CmdSubst:
+ walkStmts(x.Stmts, x.Last, f)
+ case *ParamExp:
+ Walk(x.Param, f)
+ if x.Index != nil {
+ Walk(x.Index, f)
+ }
+ if x.Repl != nil {
+ if x.Repl.Orig != nil {
+ Walk(x.Repl.Orig, f)
+ }
+ if x.Repl.With != nil {
+ Walk(x.Repl.With, f)
+ }
+ }
+ if x.Exp != nil && x.Exp.Word != nil {
+ Walk(x.Exp.Word, f)
+ }
+ case *ArithmExp:
+ Walk(x.X, f)
+ case *ArithmCmd:
+ Walk(x.X, f)
+ case *BinaryArithm:
+ Walk(x.X, f)
+ Walk(x.Y, f)
+ case *BinaryTest:
+ Walk(x.X, f)
+ Walk(x.Y, f)
+ case *UnaryArithm:
+ Walk(x.X, f)
+ case *UnaryTest:
+ Walk(x.X, f)
+ case *ParenArithm:
+ Walk(x.X, f)
+ case *ParenTest:
+ Walk(x.X, f)
+ case *CaseClause:
+ Walk(x.Word, f)
+ for _, ci := range x.Items {
+ Walk(ci, f)
+ }
+ for _, c := range x.Last {
+ Walk(&c, f)
+ }
+ case *CaseItem:
+ for _, c := range x.Comments {
+ if c.Pos().After(x.Pos()) {
+ defer Walk(&c, f)
+ break
+ }
+ Walk(&c, f)
+ }
+ walkWords(x.Patterns, f)
+ walkStmts(x.Stmts, x.Last, f)
+ case *TestClause:
+ Walk(x.X, f)
+ case *DeclClause:
+ for _, a := range x.Args {
+ Walk(a, f)
+ }
+ case *ArrayExpr:
+ for _, el := range x.Elems {
+ Walk(el, f)
+ }
+ for _, c := range x.Last {
+ Walk(&c, f)
+ }
+ case *ArrayElem:
+ for _, c := range x.Comments {
+ if c.Pos().After(x.Pos()) {
+ defer Walk(&c, f)
+ break
+ }
+ Walk(&c, f)
+ }
+ if x.Index != nil {
+ Walk(x.Index, f)
+ }
+ if x.Value != nil {
+ Walk(x.Value, f)
+ }
+ case *ExtGlob:
+ Walk(x.Pattern, f)
+ case *ProcSubst:
+ walkStmts(x.Stmts, x.Last, f)
+ case *TimeClause:
+ if x.Stmt != nil {
+ Walk(x.Stmt, f)
+ }
+ case *CoprocClause:
+ if x.Name != nil {
+ Walk(x.Name, f)
+ }
+ Walk(x.Stmt, f)
+ case *LetClause:
+ for _, expr := range x.Exprs {
+ Walk(expr, f)
+ }
+ case *TestDecl:
+ Walk(x.Description, f)
+ Walk(x.Body, f)
+ default:
+ panic(fmt.Sprintf("syntax.Walk: unexpected node type %T", x))
+ }
+
+ f(nil)
+}
+
+// DebugPrint prints the provided syntax tree, spanning multiple lines and with
+// indentation. Can be useful to investigate the content of a syntax tree.
+func DebugPrint(w io.Writer, node Node) error {
+ p := debugPrinter{out: w}
+ p.print(reflect.ValueOf(node))
+ return p.err
+}
+
+type debugPrinter struct {
+ out io.Writer
+ level int
+ err error
+}
+
+func (p *debugPrinter) printf(format string, args ...interface{}) {
+ _, err := fmt.Fprintf(p.out, format, args...)
+ if err != nil && p.err == nil {
+ p.err = err
+ }
+}
+
+func (p *debugPrinter) newline() {
+ p.printf("\n")
+ for i := 0; i < p.level; i++ {
+ p.printf(". ")
+ }
+}
+
+func (p *debugPrinter) print(x reflect.Value) {
+ switch x.Kind() {
+ case reflect.Interface:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+ p.print(x.Elem())
+ case reflect.Ptr:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+ p.printf("*")
+ p.print(x.Elem())
+ case reflect.Slice:
+ p.printf("%s (len = %d) {", x.Type(), x.Len())
+ if x.Len() > 0 {
+ p.level++
+ p.newline()
+ for i := 0; i < x.Len(); i++ {
+ p.printf("%d: ", i)
+ p.print(x.Index(i))
+ if i == x.Len()-1 {
+ p.level--
+ }
+ p.newline()
+ }
+ }
+ p.printf("}")
+
+ case reflect.Struct:
+ if v, ok := x.Interface().(Pos); ok {
+ p.printf("%v:%v", v.Line(), v.Col())
+ return
+ }
+ t := x.Type()
+ p.printf("%s {", t)
+ p.level++
+ p.newline()
+ for i := 0; i < t.NumField(); i++ {
+ p.printf("%s: ", t.Field(i).Name)
+ p.print(x.Field(i))
+ if i == x.NumField()-1 {
+ p.level--
+ }
+ p.newline()
+ }
+ p.printf("}")
+ default:
+ p.printf("%#v", x.Interface())
+ }
+}