diff --git a/README.md b/README.md index 4e9adf85f..84afce541 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,10 @@ See also [building from source](https://miller.readthedocs.io/en/latest/build.ht # Build status -[](https://github.com/johnkerl/miller/actions) +[](https://github.com/johnkerl/miller/actions) +[](https://github.com/johnkerl/miller/actions) +[](https://github.com/johnkerl/miller/actions) +[](https://github.com/johnkerl/miller/actions) # Building from source diff --git a/cmd/experiments/colors/main.go b/cmd/experiments/colors/main.go new file mode 100644 index 000000000..305fa6062 --- /dev/null +++ b/cmd/experiments/colors/main.go @@ -0,0 +1,43 @@ +// This is the entry point for the mlr executable. +package main + +import ( + "fmt" + "github.com/johnkerl/miller/internal/pkg/colorizer" +) + +const boldString = "\u001b[1m" +const underlineString = "\u001b[4m" +const reversedString = "\u001b[7m" +const redString = "\u001b[1;31m" +const blueString = "\u001b[1;34m" +const defaultString = "\u001b[0m" + +func main() { + fmt.Printf("Hello, world!\n") + + fmt.Printf("1. before %s during %s after\n", "", "") + fmt.Printf("4. before %s during %s after\n", boldString, defaultString) + fmt.Printf("2. before %s during %s after\n", redString, defaultString) + fmt.Printf("3. before %s during %s after\n", blueString, defaultString) + fmt.Printf("5. before %s during %s after\n", redString+boldString, defaultString) + fmt.Printf("7. before %s during %s after\n", blueString, defaultString) + fmt.Printf("8. before %s during %s after\n", boldString, defaultString) + fmt.Printf("9. before %s during %s after\n", boldString, defaultString) + fmt.Println() + + names := []string{ + "plain", + "red", + "bold", + "bold-red", + "red-bold", + "blue-underline", + "208", + "reversed-208", + } + for _, name := range names { + colorizer.SetKeyColor(name) + fmt.Printf("testing: [%s]\n", colorizer.MaybeColorizeKey(name, true)) + } +} diff --git a/docs/src/manpage.md b/docs/src/manpage.md index 9492fe5b1..e7327a694 100644 --- a/docs/src/manpage.md +++ b/docs/src/manpage.md @@ -621,8 +621,11 @@ OUTPUT-COLORIZATION FLAGS If environment-variable settings and command-line flags are both provided, the latter take precedence. - Please do mlr `--list-color-codes` to see the available color codes (like 170), - and `mlr --list-color-names` to see available names (like `orchid`). + Colors can be specified using names such as "red" or "orchid": please see + `mlr --list-color-names` to see available names. They can also be specified using + numbers in the range 0..255, like 170: please see `mlr --list-color-codes`. + You can also use "bold", "underline", and/or "reverse". Additionally, combinations of + those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. --always-color or -C Instructs Miller to colorize output even when it normally would not. Useful for piping output to `less @@ -3131,5 +3134,5 @@ SEE ALSO - 2022-01-27 MILLER(1) + 2022-01-30 MILLER(1) diff --git a/docs/src/manpage.txt b/docs/src/manpage.txt index bdba32306..456700526 100644 --- a/docs/src/manpage.txt +++ b/docs/src/manpage.txt @@ -600,8 +600,11 @@ OUTPUT-COLORIZATION FLAGS If environment-variable settings and command-line flags are both provided, the latter take precedence. - Please do mlr `--list-color-codes` to see the available color codes (like 170), - and `mlr --list-color-names` to see available names (like `orchid`). + Colors can be specified using names such as "red" or "orchid": please see + `mlr --list-color-names` to see available names. They can also be specified using + numbers in the range 0..255, like 170: please see `mlr --list-color-codes`. + You can also use "bold", "underline", and/or "reverse". Additionally, combinations of + those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. --always-color or -C Instructs Miller to colorize output even when it normally would not. Useful for piping output to `less @@ -3110,4 +3113,4 @@ SEE ALSO - 2022-01-27 MILLER(1) + 2022-01-30 MILLER(1) diff --git a/docs/src/output-colorization.md b/docs/src/output-colorization.md index b7147b3d6..4b824a54e 100644 --- a/docs/src/output-colorization.md +++ b/docs/src/output-colorization.md @@ -16,7 +16,11 @@ Quick links: # Output colorization -As of version 6.0.0, Miller supports output-colorization. Here are examples using side-by-side black-background and white-background terminals: +As of version 6.0.0, Miller supports output colorization. This includes colors +per se, as well as bold, underline, and/or reverse. As of version 6.1.0, the +default is bold+underline for keys -- this works well as a default regardless +of your terminal's color settings -- with further customization options as +described below:  @@ -37,8 +41,6 @@ As of version 6.0.0, Miller supports output-colorization. Here are examples usin * NIDX output format (plain text, Unix-style, with implicitly positionally indexed fields) is not colored. This is because in other formats, keys are one color and values are another. For NIDX, all output is values. -* The default colors were chosen since they look OK with white or black terminal background, and are differentiable with common varieties of human color vision. - ## Mechanisms for colorization * Miller uses ANSI escape sequences only. This does not work on Windows except on Cygwin. diff --git a/docs/src/output-colorization.md.in b/docs/src/output-colorization.md.in index 9ce149604..95baa76ab 100644 --- a/docs/src/output-colorization.md.in +++ b/docs/src/output-colorization.md.in @@ -1,6 +1,10 @@ # Output colorization -As of version 6.0.0, Miller supports output-colorization. Here are examples using side-by-side black-background and white-background terminals: +As of version 6.0.0, Miller supports output colorization. This includes colors +per se, as well as bold, underline, and/or reverse. As of version 6.1.0, the +default is bold+underline for keys -- this works well as a default regardless +of your terminal's color settings -- with further customization options as +described below:  @@ -21,8 +25,6 @@ As of version 6.0.0, Miller supports output-colorization. Here are examples usin * NIDX output format (plain text, Unix-style, with implicitly positionally indexed fields) is not colored. This is because in other formats, keys are one color and values are another. For NIDX, all output is values. -* The default colors were chosen since they look OK with white or black terminal background, and are differentiable with common varieties of human color vision. - ## Mechanisms for colorization * Miller uses ANSI escape sequences only. This does not work on Windows except on Cygwin. diff --git a/docs/src/pix/colorization.png b/docs/src/pix/colorization.png index 0909e7bd7..68f67fd81 100644 Binary files a/docs/src/pix/colorization.png and b/docs/src/pix/colorization.png differ diff --git a/docs/src/pix/colorization.png.000 b/docs/src/pix/colorization.png.000 deleted file mode 100644 index 005d8edeb..000000000 Binary files a/docs/src/pix/colorization.png.000 and /dev/null differ diff --git a/docs/src/pix/colorization2.png.000 b/docs/src/pix/colorization2.png.000 deleted file mode 100644 index 935793a60..000000000 Binary files a/docs/src/pix/colorization2.png.000 and /dev/null differ diff --git a/docs/src/reference-main-flag-list.md b/docs/src/reference-main-flag-list.md index 91766b37e..a32a6615b 100644 --- a/docs/src/reference-main-flag-list.md +++ b/docs/src/reference-main-flag-list.md @@ -327,8 +327,11 @@ How you can control colorization: If environment-variable settings and command-line flags are both provided, the latter take precedence. -Please do mlr `--list-color-codes` to see the available color codes (like 170), -and `mlr --list-color-names` to see available names (like `orchid`). +Colors can be specified using names such as "red" or "orchid": please see +`mlr --list-color-names` to see available names. They can also be specified using +numbers in the range 0..255, like 170: please see `mlr --list-color-codes`. +You can also use "bold", "underline", and/or "reverse". Additionally, combinations of +those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. **Flags:** diff --git a/docs/src/scripting.md b/docs/src/scripting.md index aa67d8db0..29cac3fb7 100644 --- a/docs/src/scripting.md +++ b/docs/src/scripting.md @@ -65,7 +65,7 @@ Key points here: Then you can do
-example-shell-script example.csv +./example-shell-script example.csv
shape count count_fraction @@ -75,7 +75,7 @@ circle 3 0.3
-cat example.csv | example-shell-script +cat example.csv | ./example-shell-script
shape count count_fraction @@ -85,7 +85,7 @@ circle 3 0.3
-example-shell-script --ojson example.csv +./example-shell-script --ojson example.csv
[ @@ -108,7 +108,7 @@ circle 3 0.3
-example-shell-script --ojson then filter '$count == 3' example.csv +./example-shell-script --ojson then filter '$count == 3' example.csv
[ @@ -132,7 +132,7 @@ etc. Here instead of putting `#!/bin/bash` on the first line, we can put `mlr` directly:-cat example-mlr-s-script +cat ./example-mlr-s-script#!/usr/bin/env mlr -s @@ -153,7 +153,7 @@ Points: Then you can do-example-mlr-s-script example.csv +./example-mlr-s-script example.csvshape count count_fraction @@ -163,7 +163,7 @@ circle 3 0.3-cat example.csv | example-mlr-s-script +cat example.csv | ./example-mlr-s-scriptshape count count_fraction @@ -173,7 +173,7 @@ circle 3 0.3-example-mlr-s-script --ojson example.csv +./example-mlr-s-script --ojson example.csv[ @@ -196,7 +196,7 @@ circle 3 0.3-example-mlr-s-script --ojson then filter '$count == 3' example.csv +./example-mlr-s-script --ojson then filter '$count == 3' example.csv[ diff --git a/docs/src/scripting.md.in b/docs/src/scripting.md.in index 6ab7933ec..0e4afc9ac 100644 --- a/docs/src/scripting.md.in +++ b/docs/src/scripting.md.in @@ -35,19 +35,19 @@ Key points here: Then you can do GENMD-RUN-COMMAND -example-shell-script example.csv +./example-shell-script example.csv GENMD-EOF GENMD-RUN-COMMAND -cat example.csv | example-shell-script +cat example.csv | ./example-shell-script GENMD-EOF GENMD-RUN-COMMAND -example-shell-script --ojson example.csv +./example-shell-script --ojson example.csv GENMD-EOF GENMD-RUN-COMMAND -example-shell-script --ojson then filter '$count == 3' example.csv +./example-shell-script --ojson then filter '$count == 3' example.csv GENMD-EOF etc. @@ -57,7 +57,7 @@ etc. Here instead of putting `#!/bin/bash` on the first line, we can put `mlr` directly: GENMD-RUN-COMMAND -cat example-mlr-s-script +cat ./example-mlr-s-script GENMD-EOF Points: @@ -71,19 +71,19 @@ Points: Then you can do GENMD-RUN-COMMAND -example-mlr-s-script example.csv +./example-mlr-s-script example.csv GENMD-EOF GENMD-RUN-COMMAND -cat example.csv | example-mlr-s-script +cat example.csv | ./example-mlr-s-script GENMD-EOF GENMD-RUN-COMMAND -example-mlr-s-script --ojson example.csv +./example-mlr-s-script --ojson example.csv GENMD-EOF GENMD-RUN-COMMAND -example-mlr-s-script --ojson then filter '$count == 3' example.csv +./example-mlr-s-script --ojson then filter '$count == 3' example.csv GENMD-EOF ## Miller scripts on Windows diff --git a/go.mod b/go.mod index 8f7e1f5e9..cd3efaa2a 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,14 @@ module github.com/johnkerl/miller // * go build github.com/johnkerl/miller/cmd/mlr // * go install github.com/johnkerl/miller/cmd/mlr +// go get github.com/johnkerl/lumin@v1.0.0 +// Local development: +// replace github.com/johnkerl/lumin => /Users/kerl/git/johnkerl/lumin + go 1.15 require ( - github.com/goccmack/gocc v0.0.0-20211213154817-7ea699349eca // indirect + github.com/johnkerl/lumin v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/lestrrat-go/strftime v1.0.5 github.com/mattn/go-isatty v0.0.14 diff --git a/go.sum b/go.sum index 0ddbd2245..b00489b38 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/goccmack/gocc v0.0.0-20211213154817-7ea699349eca h1:NuA6w6b01Ojdig+4K1l9p4Pp3unlv4owphbOiENm8m4= -github.com/goccmack/gocc v0.0.0-20211213154817-7ea699349eca/go.mod h1:c4Mb67Mg9+pl6OlxvnFBUiiQOSlXfh0QukINLl54OD0= +github.com/johnkerl/lumin v1.0.0 h1:CV34cHZOJ92Y02RbQ0rd4gA0C06Qck9q8blOyaPoWpU= +github.com/johnkerl/lumin v1.0.0/go.mod h1:eLf5AdQOaLvzZ2zVy4REr/DSeEwG+CZreHwNLICqv9E= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -20,38 +20,12 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/internal/pkg/cli/option_parse.go b/internal/pkg/cli/option_parse.go index b9ed6d944..900728369 100644 --- a/internal/pkg/cli/option_parse.go +++ b/internal/pkg/cli/option_parse.go @@ -2452,8 +2452,11 @@ How you can control colorization: If environment-variable settings and command-line flags are both provided, the latter take precedence. -Please do mlr ` + "`--list-color-codes`" + ` to see the available color codes (like 170), -and ` + "`mlr --list-color-names`" + ` to see available names (like ` + "`orchid`" + `). +Colors can be specified using names such as "red" or "orchid": please see +` + "`mlr --list-color-names`" + ` to see available names. They can also be specified using +numbers in the range 0..255, like 170: please see ` + "`mlr --list-color-codes`" + `. +You can also use "bold", "underline", and/or "reverse". Additionally, combinations of +those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. `) } diff --git a/internal/pkg/colorizer/colorizer.go b/internal/pkg/colorizer/colorizer.go index d04eb7934..2438aa949 100644 --- a/internal/pkg/colorizer/colorizer.go +++ b/internal/pkg/colorizer/colorizer.go @@ -9,10 +9,9 @@ package colorizer import ( - "fmt" "os" - "strconv" + lumin "github.com/johnkerl/lumin/pkg/colors" "github.com/mattn/go-isatty" ) @@ -35,51 +34,51 @@ func SetColorization(arg TOutputColorization) { // For command-line flags like --pass-color 208 etc func SetKeyColor(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - keyColorString = makeColorString(code) + keyColorString = escape } return ok } func SetValueColor(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - valueColorString = makeColorString(code) + valueColorString = escape } return ok } func SetPassColor(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - passColorString = makeColorString(code) + passColorString = escape } return ok } func SetFailColor(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - failColorString = makeColorString(code) + failColorString = escape } return ok } func SetREPLPS1Color(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - replPS1ColorString = makeColorString(code) + replPS1ColorString = escape } return ok } func SetREPLPS2Color(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - replPS2ColorString = makeColorString(code) + replPS2ColorString = escape } return ok } func SetHelpColor(name string) bool { - code, ok := makeColorCodeFromName(name) + escape, ok := lumin.MakeANSIEscapesFromName(name) if ok { - helpColorString = makeColorString(code) + helpColorString = escape } return ok } @@ -116,61 +115,81 @@ func MaybeColorizeHelp(text string, outputIsStdout bool) string { // ListColorCodes shows codes in the range 0..255. // For --list-color-codes command-line flag. func ListColorCodes() { - fmt.Println("Available color codes:") - for i := 0; i <= 255; i++ { - fmt.Printf("%s%3d%s", makeColorString(i), i, defaultColorString) - if i%16 < 15 { - fmt.Print(" ") - } else { - fmt.Print("\n") - } - } + lumin.ListColorCodes() } // ListColorNames shows names for codes in the range 0..255. // For --list-color-names command-line flag. func ListColorNames() { - fmt.Println("Available color names:") - for _, pair := range namesAndCodes { - fmt.Printf( - "%s%-20s%s %d\n", - makeColorString(pair.code), pair.name, defaultColorString, pair.code, - ) + lumin.ListColorNames() +} + +// ================================================================ +// Internal implementation + +func maybeColorize(text string, colorString string, outputIsStdout bool) string { + if outputIsStdout && stdoutIsATTY { + if colorization == ColorizeOutputNever { + return text + } else { + return colorize(text, colorString) + } + } else { + if colorization == ColorizeOutputAlways { + return colorize(text, colorString) + } else { + return text + } } } -// makeColorCodeFromName looks up a named code, if available: e.g. "orchid" -// maps to 170. -func makeColorCodeFromName(name string) (int, bool) { - // Things like "170" - code, err := strconv.Atoi(name) - if err == nil { - return code, true - } +func colorize(text string, colorString string) string { + return colorString + text + defaultColorString +} - // Things like "orchid" - for _, pair := range namesAndCodes { - if pair.name == name { - return pair.code, true +// GetColorization is for the CSV writer +func GetColorization(outputIsStdout bool, isKey bool) (string, string) { + if outputIsStdout && stdoutIsATTY { + if colorization == ColorizeOutputNever { + return "", "" + } else { + if isKey { + return keyColorString, defaultColorString + } else { + return valueColorString, defaultColorString + } + } + } else { + if colorization == ColorizeOutputAlways { + if isKey { + return keyColorString, defaultColorString + } else { + return valueColorString, defaultColorString + } + } else { + return "", "" } } - return -1, false } // ================================================================ // Internal implementation // Default ANSI color codes -var keyColorString = make256ColorString(208) // orange -var valueColorString = make256ColorString(33) // blue -var passColorString = make16ColorString(10) // bold green -var failColorString = make16ColorString(9) // bold red -var replPS1ColorString = make16ColorString(9) // bold red -var replPS2ColorString = make16ColorString(1) // red -var helpColorString = make16ColorString(9) // bold red +// 6.0.0: +// var keyColorString = lumin.MakeANSIEscapesFromNameUnconditionally("orange") +// var valueColorString = lumin.MakeANSIEscapesFromNameUnconditionally("blue") +// 6.1.0: +var keyColorString = lumin.MakeANSIEscapesFromNameUnconditionally("bold-underline") +var valueColorString = lumin.MakeANSIEscapesFromNameUnconditionally("plain") +var passColorString = lumin.MakeANSIEscapesFromNameUnconditionally("bold-lime") +var failColorString = lumin.MakeANSIEscapesFromNameUnconditionally("bold-red") +var replPS1ColorString = lumin.MakeANSIEscapesFromNameUnconditionally("bold-red") +var replPS2ColorString = lumin.MakeANSIEscapesFromNameUnconditionally("red") +var helpColorString = lumin.MakeANSIEscapesFromNameUnconditionally("bold-red") // Used to switch back to default color -var defaultColorString = "\033[0m" +var defaultColorString = "\u001b[0m" // Default: colorize if writing to stdout and if stdout is a TTY var colorization TOutputColorization = ColorizeOutputIfTTY @@ -218,6 +237,15 @@ func init() { } } +func makeColorStringFromEnv(envName string) (string, bool) { + envValue := os.Getenv(envName) + if envValue == "" { + return "", false + } + + return lumin.MakeANSIEscapesFromName(envValue) +} + func getStdoutIsATTY() bool { // Don't try ANSI color on Windows (except Cygwin) if os.Getenv("TERM") == "" { @@ -231,366 +259,3 @@ func getStdoutIsATTY() bool { } return false } - -// make16ColorString constructs an ANSI-16-color-mode escape sequence -func make16ColorString(i int) string { - i &= 15 - boldBit := (i >> 3) & 1 - colorBits := i & 7 - return fmt.Sprintf("\033[%d;%dm", boldBit, 30+colorBits) -} - -// make256ColorString constructs an ANSI-256-color-mode escape sequence -func make256ColorString(i int) string { - i &= 255 - return fmt.Sprintf("\033[1;38;5;%dm", i&255) -} - -// makeColorString constructs an ANSI-16-color-mode escape sequence if arg is -// in 0..15, else ANSI-256-color-mode escape sequence -func makeColorString(i int) string { - if 0 <= i && i <= 15 { - return make16ColorString(i) - } else { - return make256ColorString(i) - } -} - -func makeColorStringFromEnv(envName string) (string, bool) { - envValue := os.Getenv(envName) - if envValue == "" { - return "", false - } - code, ok := makeColorCodeFromName(envValue) - if !ok { - return "", false // TODO: return error? - } - if code < 0 { - return "", false // TODO: return error? - } - code &= 255 - return makeColorString(code), true -} - -func maybeColorize(text string, colorString string, outputIsStdout bool) string { - if outputIsStdout && stdoutIsATTY { - if colorization == ColorizeOutputNever { - return text - } else { - return colorize(text, colorString) - } - } else { - if colorization == ColorizeOutputAlways { - return colorize(text, colorString) - } else { - return text - } - } -} - -func colorize(text string, colorString string) string { - return colorString + text + defaultColorString -} - -// GetColorization is for the CSV writer -func GetColorization(outputIsStdout bool, isKey bool) (string, string) { - if outputIsStdout && stdoutIsATTY { - if colorization == ColorizeOutputNever { - return "", "" - } else { - if isKey { - return keyColorString, defaultColorString - } else { - return valueColorString, defaultColorString - } - } - } else { - if colorization == ColorizeOutputAlways { - if isKey { - return keyColorString, defaultColorString - } else { - return valueColorString, defaultColorString - } - } else { - return "", "" - } - } -} - -// ---------------------------------------------------------------- -// Name-to-code lookup table. -// -// Source: https://jonasjacek.github.io/colors/ -// -// This is intentionally an array, not a map. -// -// Map would be more efficient for lookup but maps do not preserve -// insertion-ordering in Go -- so, doing 'list colors' would print them in a -// random order. To do nice 'list colors' we'd have to put them in this kind of -// array and sort anyway. Also, lookups are done exactly once at program start -// -- so, it's more efficient to make this an array with lookup by search, than -// to populate a hash-map (computing hashcodes) for a use-once hash lookup. - -type tNameAndCode struct { - name string - code int -} - -var namesAndCodes = []tNameAndCode{ - {"aqua", 14}, - {"aquamarine1", 122}, - // {"aquamarine1", 86}, // duplicate - {"aquamarine3", 79}, - {"black", 0}, - {"blue", 12}, - {"blue1", 21}, - {"blue3", 19}, - // {"blue3", 20}, // duplicate - {"blueviolet", 57}, - {"cadetblue", 72}, - // {"cadetblue", 73}, // duplicate - {"chartreuse1", 118}, - {"chartreuse2", 112}, - // {"chartreuse2", 82}, // duplicate - {"chartreuse3", 70}, - // {"chartreuse3", 76}, // duplicate - {"chartreuse4", 64}, - {"cornflowerblue", 69}, - {"cornsilk1", 230}, - {"cyan1", 51}, - {"cyan2", 50}, - {"cyan3", 43}, - {"darkblue", 18}, - {"darkcyan", 36}, - {"darkgoldenrod", 136}, - {"darkgreen", 22}, - {"darkkhaki", 143}, - {"darkmagenta", 90}, - // {"darkmagenta", 91}, // duplicate - {"darkolivegreen1", 191}, - // {"darkolivegreen1", 192}, // duplicate - {"darkolivegreen2", 155}, - {"darkolivegreen3", 107}, - // {"darkolivegreen3", 113}, // duplicate - // {"darkolivegreen3", 149}, // duplicate - {"darkorange", 208}, - {"darkorange3", 130}, - // {"darkorange3", 166}, // duplicate - {"darkred", 52}, - // {"darkred", 88}, // duplicate - {"darkseagreen", 108}, - {"darkseagreen1", 158}, - // {"darkseagreen1", 193}, // duplicate - {"darkseagreen2", 151}, - // {"darkseagreen2", 157}, // duplicate - {"darkseagreen3", 115}, - // {"darkseagreen3", 150}, // duplicate - {"darkseagreen4", 65}, - // {"darkseagreen4", 71}, // duplicate - {"darkslategray1", 123}, - {"darkslategray2", 87}, - {"darkslategray3", 116}, - {"darkturquoise", 44}, - {"darkviolet", 128}, - // {"darkviolet", 92}, // duplicate - {"deeppink1", 198}, - // {"deeppink1", 199}, // duplicate - {"deeppink2", 197}, - {"deeppink3", 161}, - // {"deeppink3", 162}, // duplicate - {"deeppink4", 125}, - // {"deeppink4", 53}, // duplicate - // {"deeppink4", 89}, // duplicate - {"deepskyblue1", 39}, - {"deepskyblue2", 38}, - {"deepskyblue3", 31}, - // {"deepskyblue3", 32}, // duplicate - {"deepskyblue4", 23}, - // {"deepskyblue4", 24}, // duplicate - // {"deepskyblue4", 25}, // duplicate - {"dodgerblue1", 33}, - {"dodgerblue2", 27}, - {"dodgerblue3", 26}, - {"fuchsia", 13}, - {"gold1", 220}, - {"gold3", 142}, - // {"gold3", 178}, // duplicate - {"green", 2}, - {"green1", 46}, - {"green3", 34}, - // {"green3", 40}, // duplicate - {"green4", 28}, - {"greenyellow", 154}, - {"grey", 8}, - {"grey0", 16}, - {"grey100", 231}, - {"grey11", 234}, - {"grey15", 235}, - {"grey19", 236}, - {"grey23", 237}, - {"grey27", 238}, - {"grey3", 232}, - {"grey30", 239}, - {"grey35", 240}, - {"grey37", 59}, - {"grey39", 241}, - {"grey42", 242}, - {"grey46", 243}, - {"grey50", 244}, - {"grey53", 102}, - {"grey54", 245}, - {"grey58", 246}, - {"grey62", 247}, - {"grey63", 139}, - {"grey66", 248}, - {"grey69", 145}, - {"grey7", 233}, - {"grey70", 249}, - {"grey74", 250}, - {"grey78", 251}, - {"grey82", 252}, - {"grey84", 188}, - {"grey85", 253}, - {"grey89", 254}, - {"grey93", 255}, - {"honeydew2", 194}, - {"hotpink", 205}, - // {"hotpink", 206}, // duplicate - {"hotpink2", 169}, - {"hotpink3", 132}, - // {"hotpink3", 168}, // duplicate - {"indianred", 131}, - // {"indianred", 167}, // duplicate - {"indianred1", 203}, - // {"indianred1", 204}, // duplicate - {"khaki1", 228}, - {"khaki3", 185}, - {"lightcoral", 210}, - {"lightcyan1", 195}, - {"lightcyan3", 152}, - {"lightgoldenrod1", 227}, - {"lightgoldenrod2", 186}, - // {"lightgoldenrod2", 221}, // duplicate - // {"lightgoldenrod2", 222}, // duplicate - {"lightgoldenrod3", 179}, - {"lightgreen", 119}, - // {"lightgreen", 120}, // duplicate - {"lightpink1", 217}, - {"lightpink3", 174}, - {"lightpink4", 95}, - {"lightsalmon1", 216}, - {"lightsalmon3", 137}, - // {"lightsalmon3", 173}, // duplicate - {"lightseagreen", 37}, - {"lightskyblue1", 153}, - {"lightskyblue3", 109}, - // {"lightskyblue3", 110}, // duplicate - {"lightslateblue", 105}, - {"lightslategrey", 103}, - {"lightsteelblue", 147}, - {"lightsteelblue1", 189}, - {"lightsteelblue3", 146}, - {"lightyellow3", 187}, - {"lime", 10}, - {"magenta1", 201}, - {"magenta2", 165}, - //{"magenta2", 200}, // duplicate - {"magenta3", 127}, - // {"magenta3", 163}, // duplicate - // {"magenta3", 164}, // duplicate - {"maroon", 1}, - {"mediumorchid", 134}, - {"mediumorchid1", 171}, - // {"mediumorchid1", 207}, // duplicate - {"mediumorchid3", 133}, - {"mediumpurple", 104}, - {"mediumpurple1", 141}, - {"mediumpurple2", 135}, - // {"mediumpurple2", 140}, // duplicate - {"mediumpurple3", 97}, - // {"mediumpurple3", 98}, // duplicate - {"mediumpurple4", 60}, - {"mediumspringgreen", 49}, - {"mediumturquoise", 80}, - {"mediumvioletred", 126}, - {"mistyrose1", 224}, - {"mistyrose3", 181}, - {"navajowhite1", 223}, - {"navajowhite3", 144}, - {"navy", 4}, - {"navyblue", 17}, - {"olive", 3}, - {"orange1", 214}, - {"orange3", 172}, - {"orange4", 58}, - // {"orange4", 94}, // duplicate - {"orangered1", 202}, - {"orchid", 170}, - {"orchid1", 213}, - {"orchid2", 212}, - {"palegreen1", 121}, - // {"palegreen1", 156}, // duplicate - {"palegreen3", 114}, - // {"palegreen3", 77}, // duplicate - {"paleturquoise1", 159}, - {"paleturquoise4", 66}, - {"palevioletred1", 211}, - {"pink1", 218}, - {"pink3", 175}, - {"plum1", 219}, - {"plum2", 183}, - {"plum3", 176}, - {"plum4", 96}, - {"purple", 129}, - //{"purple", 5}, // duplicate - //{"purple", 93}, // duplicate - {"purple3", 56}, - {"purple4", 54}, - //{"purple4", 55}, // duplicate - {"red", 9}, - {"red1", 196}, - {"red3", 124}, - //{"red3", 160}, // duplicate - {"rosybrown", 138}, - {"royalblue1", 63}, - {"salmon1", 209}, - {"sandybrown", 215}, - {"seagreen1", 84}, - //{"seagreen1", 85}, // duplicate - {"seagreen2", 83}, - {"seagreen3", 78}, - {"silver", 7}, - {"skyblue1", 117}, - {"skyblue2", 111}, - {"skyblue3", 74}, - {"slateblue1", 99}, - {"slateblue3", 61}, - //{"slateblue3", 62}, // duplicate - {"springgreen1", 48}, - {"springgreen2", 42}, - //{"springgreen2", 47}, // duplicate - {"springgreen3", 35}, - //{"springgreen3", 41}, // duplicate - {"springgreen4", 29}, - {"steelblue", 67}, - {"steelblue1", 75}, - //{"steelblue1", 81}, // duplicate - {"steelblue3", 68}, - {"tan", 180}, - {"teal", 6}, - {"thistle1", 225}, - {"thistle3", 182}, - {"turquoise2", 45}, - {"turquoise4", 30}, - {"violet", 177}, - {"wheat1", 229}, - {"wheat4", 101}, - {"white", 15}, - {"yellow", 11}, - {"yellow1", 226}, - {"yellow2", 190}, - {"yellow3", 148}, - //{"yellow3", 184}, // duplicate - {"yellow4", 100}, - //{"yellow4", 106}, // duplicate -} diff --git a/man/manpage.txt b/man/manpage.txt index bdba32306..456700526 100644 --- a/man/manpage.txt +++ b/man/manpage.txt @@ -600,8 +600,11 @@ OUTPUT-COLORIZATION FLAGS If environment-variable settings and command-line flags are both provided, the latter take precedence. - Please do mlr `--list-color-codes` to see the available color codes (like 170), - and `mlr --list-color-names` to see available names (like `orchid`). + Colors can be specified using names such as "red" or "orchid": please see + `mlr --list-color-names` to see available names. They can also be specified using + numbers in the range 0..255, like 170: please see `mlr --list-color-codes`. + You can also use "bold", "underline", and/or "reverse". Additionally, combinations of + those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. --always-color or -C Instructs Miller to colorize output even when it normally would not. Useful for piping output to `less @@ -3110,4 +3113,4 @@ SEE ALSO - 2022-01-27 MILLER(1) + 2022-01-30 MILLER(1) diff --git a/man/mlr.1 b/man/mlr.1 index 57011f3e4..52cd18b35 100644 --- a/man/mlr.1 +++ b/man/mlr.1 @@ -2,12 +2,12 @@ .\" Title: mlr .\" Author: [see the "AUTHOR" section] .\" Generator: ./mkman.rb -.\" Date: 2022-01-27 +.\" Date: 2022-01-30 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "MILLER" "1" "2022-01-27" "\ \&" "\ \&" +.TH "MILLER" "1" "2022-01-30" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Portability definitions .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -719,8 +719,11 @@ How you can control colorization: If environment-variable settings and command-line flags are both provided, the latter take precedence. -Please do mlr `--list-color-codes` to see the available color codes (like 170), -and `mlr --list-color-names` to see available names (like `orchid`). +Colors can be specified using names such as "red" or "orchid": please see +`mlr --list-color-names` to see available names. They can also be specified using +numbers in the range 0..255, like 170: please see `mlr --list-color-codes`. +You can also use "bold", "underline", and/or "reverse". Additionally, combinations of +those can be joined with a "-", like "red-bold", "bold-170", "bold-underline", etc. --always-color or -C Instructs Miller to colorize output even when it normally would not. Useful for piping output to `less diff --git a/todo.txt b/todo.txt index 5354f298a..7dc1b0e45 100644 --- a/todo.txt +++ b/todo.txt @@ -1,21 +1,46 @@ =============================================================== RELEASES -* follow ... * plan 6.1.0 ? w/ natural sort order ? strptime - ? split - ? fmt/unfmt/regex doc ? datediff et al. + ? mlr join --left-fields a,b,c + ? rank + ? ?foo and ??foo @ repl help + o default colors; bold/underline/reverse + o fmt/unfmt/regex doc + o FAQ/examples reorg + k array concat + k format/unformat + k split + k slwin & shift-lead +* plan 6.2.0 + k 0o.. octal literals in the DSL + ? YAML +-> more badges -- ? ================================================================ FEATURES +---------------------------------------------------------------- +* colors + o lumin import + k lumin verstag + - lumin needs bold/underline/reversed -> help; plus x-y-z syntax + k wup for local go.mod override + o RT w/ -C + o olh/webdocs x several + +---------------------------------------------------------------- +* natural sort order + https://github.com/facette/natsort + ---------------------------------------------------------------- example pages as feature catch-up: * example page for format/scan options o format/unformat + x=unformat(1,2); x; string(x); is_error(x) o strmatch o =~ * separate examples section from (new) FAQs section @@ -55,6 +80,8 @@ k better print-interpolate with {} etc ---------------------------------------------------------------- ! CSV default unsparsify ... note this must trust the *first* record ....... +* CSV: acceptance somehow for \" in place of "" + o & more flex more generally ---------------------------------------------------------------- ! quoted NIDX @@ -114,6 +141,7 @@ k better print-interpolate with {} etc UX * ?xyz and ??xyz in repl, for :help and :help find respectively +? NF? ! bnf fix for '[[' ']]' etc -- make it a nesting of singles. since otherwise no '[[3,4]]' literals :( ! broadly rethink os.Exit, especially as affecting mlr repl @@ -147,6 +175,33 @@ DOC ! link to SE table ... https://github.com/johnkerl/miller/discussions/609#discussioncomment-1115715 +* put -f link in scrpting.html +* no --load in .mlrrc b/c + https://github.com/johnkerl/miller/security/advisories/GHSA-mw2v-4q78-j2cw + (system() in begin{}) + but suggest alias + +* surface readme-versions.md @ install & tell them how to get current + o in particular, older distros won't auto-update + +* how-to-contribute @ rmd +* more clear miller docs == head + +* go version & why not generics (not all distros w/ newer go compilers) + +* document the fill-empty verb in + https://miller.readthedocs.io/en/latest/reference-main-null-data/#rules-for-null-handling + +* mlr R numpy/scipy/pandas ref. +* ffmts page <-> R read.table read.csv ... +* https://github.com/agarrharr/awesome-cli-apps#data-manipulation + +* "Miller, if I understand correctly, was born for those who already frequented + the command line, awk, for users with at least average data skills. While for + me, a basic user, it made me discover how it gives the possibility of + analyzing and transforming data, even complex ones, with a very low learning + curve." + * document cloudthings, e.g. o go.yml o codespell.yml @@ -273,10 +328,14 @@ INFO i https://en.wikipedia.org/wiki/Delimiter#Delimiter_collision +i https://framework.frictionlessdata.io/docs/tutorials/working-with-cli/ + i https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/ i go tool nm -size mlr | sort -nrk 2 +i https://go.dev/play/p/hrB77U3d0S3?v=gotip + * godoc notes: o go get golang.org/x/tools/cmd/godoc o dev mode: