From 5e308df62a0ce53d9cb75f9b6539b772b8d35971 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 08:22:49 +0000 Subject: [PATCH 01/23] chore: add command for showing colors --- cmd/cliui/main.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 161414e4471e2..1e8e2b87fa4ed 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -18,6 +18,7 @@ import ( "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" "github.com/coder/serpent" ) @@ -37,6 +38,43 @@ func main() { }, } + root.Children = append(root.Children, &serpent.Command{ + Use: "colors", + Handler: func(inv *serpent.Invocation) error { + msg := pretty.Sprint(cliui.DefaultStyles.Code, "This is a code message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Error, "This is an error message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Field, "This is a field message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Keyword, "This is a keyword message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Placeholder, "This is a placeholder message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Prompt, "This is a prompt message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Fuchsia, "This is a fuchsia prompt message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + msg = pretty.Sprint(cliui.DefaultStyles.Warn, "This is a warning message") + _, _ = fmt.Fprintln(inv.Stdout, msg) + + return nil + }, + }) + root.Children = append(root.Children, &serpent.Command{ Use: "prompt", Handler: func(inv *serpent.Invocation) error { From 86175bffb3d8825a9a8fd20bcb7d2c1445751f7d Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 08:29:24 +0000 Subject: [PATCH 02/23] fix: use ANSI color codes instead of RGB --- cli/cliui/cliui.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index db655749e94bf..5d285d45c624f 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -37,11 +37,10 @@ var ( ) var ( - Green = Color("#04B575") - Red = Color("#ED567A") - Fuchsia = Color("#EE6FF8") - Yellow = Color("#ECFD65") - Blue = Color("#5000ff") + Green = Color("2") + Red = Color("1") + Yellow = Color("3") + Blue = Color("6") ) // Color returns a color for the given string. @@ -123,7 +122,7 @@ func init() { DefaultStyles = Styles{ Code: pretty.Style{ ifTerm(pretty.XPad(1, 1)), - pretty.FgColor(Red), + pretty.FgColor(color.Color("#ED567A")), pretty.BgColor(color.Color("#2c2c2c")), }, DateTimeStamp: pretty.Style{ From 098d35d7d44b3c50c8bf0bbeaafbea850eab1cc2 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 12:01:10 +0000 Subject: [PATCH 03/23] feat: add '--no-color' flag --- cli/cliui/cliui.go | 23 +++++++++++++++++++---- cli/root.go | 6 ++++++ cmd/cliui/main.go | 8 ++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 5d285d45c624f..cdb6635abfd49 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -2,7 +2,9 @@ package cliui import ( "flag" + "fmt" "os" + "slices" "sync" "time" @@ -12,6 +14,10 @@ import ( "github.com/coder/pretty" ) +const NoColorFlag = "no-color" + +var NoColor = false + var Canceled = xerrors.New("canceled") // DefaultStyles compose visual elements of the UI. @@ -37,21 +43,30 @@ var ( ) var ( - Green = Color("2") - Red = Color("1") - Yellow = Color("3") - Blue = Color("6") + Green = Color("10") + Red = Color("9") + Yellow = Color("11") + Blue = Color("12") ) // Color returns a color for the given string. func Color(s string) termenv.Color { colorOnce.Do(func() { color = termenv.NewOutput(os.Stdout).ColorProfile() + if flag.Lookup("test.v") != nil { // Use a consistent colorless profile in tests so that results // are deterministic. color = termenv.Ascii } + + // Currently it appears there is no way to use the flag from + // serpent as it isn't possible to create a root middleware that + // runs for every command. For now we just check if `os.Args` + // has the flag. + if slices.Contains(os.Args, fmt.Sprintf("--%s", NoColorFlag)) { + color = termenv.Ascii + } }) return color.Color(s) } diff --git a/cli/root.go b/cli/root.go index 4945ecdd1656c..cc407910fd907 100644 --- a/cli/root.go +++ b/cli/root.go @@ -461,6 +461,12 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err Value: serpent.StringOf(&r.globalConfig), Group: globalGroup, }, + { + Flag: cliui.NoColorFlag, + Description: "Disable use of color in CLI output.", + Value: serpent.BoolOf(&cliui.NoColor), + Group: globalGroup, + }, { Flag: "version", // This was requested by a customer to assist with their migration. diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 1e8e2b87fa4ed..011de730e1848 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -38,6 +38,14 @@ func main() { }, } + root.Options = []serpent.Option{ + { + Default: "false", + Flag: cliui.NoColorFlag, + Value: serpent.BoolOf(&cliui.NoColor), + }, + } + root.Children = append(root.Children, &serpent.Command{ Use: "colors", Handler: func(inv *serpent.Invocation) error { From 3d130604dd17a3232a90fb4cee561c652ed206cc Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 12:03:26 +0000 Subject: [PATCH 04/23] fix: revert colors --- cli/cliui/cliui.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index cdb6635abfd49..c8a3f3107960a 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -43,10 +43,10 @@ var ( ) var ( - Green = Color("10") - Red = Color("9") - Yellow = Color("11") - Blue = Color("12") + Green = Color("2") + Red = Color("1") + Yellow = Color("3") + Blue = Color("4") ) // Color returns a color for the given string. From 5b8fa3bda2a0251630a0f8e25e3210805559ab58 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 12:40:39 +0000 Subject: [PATCH 05/23] chore: change colors --- cli/cliui/cliui.go | 24 +++++++++++++++--------- cli/cliui/select.go | 10 +++++----- cmd/cliui/main.go | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index c8a3f3107960a..0a58ac1165ddf 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -43,10 +43,13 @@ var ( ) var ( - Green = Color("2") - Red = Color("1") - Yellow = Color("3") - Blue = Color("4") + Red = Color("1") + Green = Color("2") + Yellow = Color("3") + Blue = Color("4") + Magenta = Color("5") + White = Color("7") + BrightMagenta = Color("13") ) // Color returns a color for the given string. @@ -138,10 +141,10 @@ func init() { Code: pretty.Style{ ifTerm(pretty.XPad(1, 1)), pretty.FgColor(color.Color("#ED567A")), - pretty.BgColor(color.Color("#2c2c2c")), + pretty.BgColor(color.Color("#2C2C2C")), }, DateTimeStamp: pretty.Style{ - pretty.FgColor(color.Color("#7571F9")), + pretty.FgColor(Blue), }, Error: pretty.Style{ pretty.FgColor(Red), @@ -149,16 +152,19 @@ func init() { Field: pretty.Style{ pretty.XPad(1, 1), pretty.FgColor(color.Color("#FFFFFF")), - pretty.BgColor(color.Color("#2b2a2a")), + pretty.BgColor(color.Color("#2B2A2A")), + }, + Fuchsia: pretty.Style{ + pretty.FgColor(BrightMagenta), }, Keyword: pretty.Style{ pretty.FgColor(Green), }, Placeholder: pretty.Style{ - pretty.FgColor(color.Color("#4d46b3")), + pretty.FgColor(Magenta), }, Prompt: pretty.Style{ - pretty.FgColor(color.Color("#5C5C5C")), + pretty.FgColor(White), pretty.Wrap("> ", ""), }, Warn: pretty.Style{ diff --git a/cli/cliui/select.go b/cli/cliui/select.go index 9c918bad94488..39e547c0258ea 100644 --- a/cli/cliui/select.go +++ b/cli/cliui/select.go @@ -256,7 +256,7 @@ func (m selectModel) View() string { if m.cursor == start+i { style = pretty.Style{ pretty.Wrap("> ", ""), - pretty.FgColor(Green), + DefaultStyles.Keyword, } } @@ -481,13 +481,13 @@ func (m multiSelectModel) View() string { o := option.option if m.cursor == i { - cursor = pretty.Sprint(pretty.FgColor(Green), "> ") - chosen = pretty.Sprint(pretty.FgColor(Green), "[ ]") - o = pretty.Sprint(pretty.FgColor(Green), o) + cursor = pretty.Sprint(DefaultStyles.Keyword, "> ") + chosen = pretty.Sprint(DefaultStyles.Keyword, "[ ]") + o = pretty.Sprint(DefaultStyles.Keyword, o) } if option.chosen { - chosen = pretty.Sprint(pretty.FgColor(Green), "[x]") + chosen = pretty.Sprint(DefaultStyles.Keyword, "[x]") } _, _ = s.WriteString(fmt.Sprintf( diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 011de730e1848..b477f91d893f5 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -73,7 +73,7 @@ func main() { msg = pretty.Sprint(cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message") _, _ = fmt.Fprintln(inv.Stdout, msg) - msg = pretty.Sprint(cliui.DefaultStyles.Fuchsia, "This is a fuchsia prompt message") + msg = pretty.Sprint(cliui.DefaultStyles.Fuchsia, "This is a fuchsia message") _, _ = fmt.Fprintln(inv.Stdout, msg) msg = pretty.Sprint(cliui.DefaultStyles.Warn, "This is a warning message") From 4ce84a48a4ce1a0bedc3829d37a1b7ae7ee045a8 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 12:52:28 +0000 Subject: [PATCH 06/23] fix: update golden files --- cli/cliui/cliui.go | 34 ++++++++++----------- cli/testdata/coder_--help.golden | 3 ++ docs/reference/cli/README.md | 8 +++++ enterprise/cli/testdata/coder_--help.golden | 3 ++ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 0a58ac1165ddf..39262c51ab8fa 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -43,13 +43,13 @@ var ( ) var ( - Red = Color("1") - Green = Color("2") - Yellow = Color("3") - Blue = Color("4") - Magenta = Color("5") - White = Color("7") - BrightMagenta = Color("13") + red = Color("1") + green = Color("2") + yellow = Color("3") + blue = Color("4") + magenta = Color("5") + white = Color("7") + brightMagenta = Color("13") ) // Color returns a color for the given string. @@ -126,11 +126,11 @@ func Field(s string) string { return pretty.Sprint(DefaultStyles.Field, s) } -func ifTerm(fmt pretty.Formatter) pretty.Formatter { +func ifTerm(f pretty.Formatter) pretty.Formatter { if !isTerm() { return pretty.Nop } - return fmt + return f } func init() { @@ -144,10 +144,10 @@ func init() { pretty.BgColor(color.Color("#2C2C2C")), }, DateTimeStamp: pretty.Style{ - pretty.FgColor(Blue), + pretty.FgColor(blue), }, Error: pretty.Style{ - pretty.FgColor(Red), + pretty.FgColor(red), }, Field: pretty.Style{ pretty.XPad(1, 1), @@ -155,20 +155,20 @@ func init() { pretty.BgColor(color.Color("#2B2A2A")), }, Fuchsia: pretty.Style{ - pretty.FgColor(BrightMagenta), + pretty.FgColor(brightMagenta), }, Keyword: pretty.Style{ - pretty.FgColor(Green), + pretty.FgColor(green), }, Placeholder: pretty.Style{ - pretty.FgColor(Magenta), + pretty.FgColor(magenta), }, Prompt: pretty.Style{ - pretty.FgColor(White), + pretty.FgColor(white), pretty.Wrap("> ", ""), }, Warn: pretty.Style{ - pretty.FgColor(Yellow), + pretty.FgColor(yellow), }, Wrap: pretty.Style{ pretty.LineWrap(80), @@ -177,7 +177,7 @@ func init() { DefaultStyles.FocusedPrompt = append( DefaultStyles.Prompt, - pretty.FgColor(Blue), + pretty.FgColor(blue), ) } diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index 2ebbc458e1b6b..66779a0e2fe6a 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -89,6 +89,9 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. + --no-color bool + Disable use of color in CLI output. + --no-feature-warning bool, $CODER_NO_FEATURE_WARNING Suppress warnings about unlicensed features. diff --git a/docs/reference/cli/README.md b/docs/reference/cli/README.md index 0b0331afa8273..cbe76991e4926 100644 --- a/docs/reference/cli/README.md +++ b/docs/reference/cli/README.md @@ -167,3 +167,11 @@ Disable network telemetry. Network telemetry is collected when connecting to wor | Default | ~/.config/coderv2 | Path to the global `coder` config directory. + +### --no-color + +| | | +| ---- | ----------------- | +| Type | bool | + +Disable use of color in CLI output. diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden index e575451922a5b..a25de562d1625 100644 --- a/enterprise/cli/testdata/coder_--help.golden +++ b/enterprise/cli/testdata/coder_--help.golden @@ -49,6 +49,9 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. + --no-color bool + Disable use of color in CLI output. + --no-feature-warning bool, $CODER_NO_FEATURE_WARNING Suppress warnings about unlicensed features. From a75dbb23ed7ae4a85f908256c8827187d838a5d6 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 13:46:46 +0000 Subject: [PATCH 07/23] fix: replace blue with brightBlue --- cli/cliui/cliui.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 39262c51ab8fa..f87ab1edd735b 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -46,9 +46,9 @@ var ( red = Color("1") green = Color("2") yellow = Color("3") - blue = Color("4") magenta = Color("5") white = Color("7") + brightBlue = Color("12") brightMagenta = Color("13") ) @@ -144,7 +144,7 @@ func init() { pretty.BgColor(color.Color("#2C2C2C")), }, DateTimeStamp: pretty.Style{ - pretty.FgColor(blue), + pretty.FgColor(brightBlue), }, Error: pretty.Style{ pretty.FgColor(red), @@ -177,7 +177,7 @@ func init() { DefaultStyles.FocusedPrompt = append( DefaultStyles.Prompt, - pretty.FgColor(blue), + pretty.FgColor(brightBlue), ) } From 390a7ca2940167350821829a72c5c25e79a43f2c Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 14:06:45 +0000 Subject: [PATCH 08/23] fix: drop '> ' for unfocused prompts --- cli/cliui/cliui.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index f87ab1edd735b..6584708277b8d 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -157,6 +157,11 @@ func init() { Fuchsia: pretty.Style{ pretty.FgColor(brightMagenta), }, + FocusedPrompt: pretty.Style{ + pretty.FgColor(white), + pretty.Wrap("> ", ""), + pretty.FgColor(brightBlue), + }, Keyword: pretty.Style{ pretty.FgColor(green), }, @@ -165,7 +170,7 @@ func init() { }, Prompt: pretty.Style{ pretty.FgColor(white), - pretty.Wrap("> ", ""), + pretty.Wrap(" ", ""), }, Warn: pretty.Style{ pretty.FgColor(yellow), @@ -175,10 +180,6 @@ func init() { }, } - DefaultStyles.FocusedPrompt = append( - DefaultStyles.Prompt, - pretty.FgColor(brightBlue), - ) } // ValidateNotEmpty is a helper function to disallow empty inputs! From 7e6db79fbb029cc1d320981affde19109331b630 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 14:12:57 +0000 Subject: [PATCH 09/23] fix: run 'make fmt' --- cli/cliui/cliui.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 6584708277b8d..83d214d6c16cb 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -179,7 +179,6 @@ func init() { pretty.LineWrap(80), }, } - } // ValidateNotEmpty is a helper function to disallow empty inputs! From ce913a5514a40b63766fa24b5724781431f05079 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 15:01:37 +0000 Subject: [PATCH 10/23] chore: allow disabling color with env flags --- cli/cliui/cliui.go | 5 ++++- cli/root.go | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 83d214d6c16cb..c78179bdf3e56 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -43,6 +43,7 @@ var ( ) var ( + // ANSI color codes red = Color("1") green = Color("2") yellow = Color("3") @@ -67,7 +68,9 @@ func Color(s string) termenv.Color { // serpent as it isn't possible to create a root middleware that // runs for every command. For now we just check if `os.Args` // has the flag. - if slices.Contains(os.Args, fmt.Sprintf("--%s", NoColorFlag)) { + if slices.Contains(os.Args, fmt.Sprintf("--%s", NoColorFlag)) || + os.Getenv("CODER_NO_COLOR") != "" || + os.Getenv("NO_COLOR") != "" { color = termenv.Ascii } }) diff --git a/cli/root.go b/cli/root.go index cc407910fd907..da260426d98e5 100644 --- a/cli/root.go +++ b/cli/root.go @@ -463,6 +463,7 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err }, { Flag: cliui.NoColorFlag, + Env: "CODER_NO_COLOR", Description: "Disable use of color in CLI output.", Value: serpent.BoolOf(&cliui.NoColor), Group: globalGroup, From 22a2d0b52fd9bfc6dadbbe8a9eb44dd4ecff54a3 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 15:36:30 +0000 Subject: [PATCH 11/23] fix: apply fixes from feedback --- cli/cliui/cliui.go | 3 +-- cli/root.go | 10 +++++++++- cli/testdata/coder_--help.golden | 2 +- cmd/cliui/main.go | 4 +++- enterprise/cli/testdata/coder_--help.golden | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index c78179bdf3e56..2c8d87e62916b 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -16,8 +16,6 @@ import ( const NoColorFlag = "no-color" -var NoColor = false - var Canceled = xerrors.New("canceled") // DefaultStyles compose visual elements of the UI. @@ -69,6 +67,7 @@ func Color(s string) termenv.Color { // runs for every command. For now we just check if `os.Args` // has the flag. if slices.Contains(os.Args, fmt.Sprintf("--%s", NoColorFlag)) || + slices.Contains(os.Args, fmt.Sprintf("--%s=true", NoColorFlag)) || os.Getenv("CODER_NO_COLOR") != "" || os.Getenv("NO_COLOR") != "" { color = termenv.Ascii diff --git a/cli/root.go b/cli/root.go index da260426d98e5..74956b5d5abd9 100644 --- a/cli/root.go +++ b/cli/root.go @@ -331,6 +331,13 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err r.clientURL = new(url.URL) } + // NOTE(Danielle): It appears there is no way to have a 'global' middleware in + // serpent so we manually handle the ENV/flag lookup and setup + // the option in the below OptionSet so it is documented. + // We use (and discard) this local variable to get the correct + // behavior from the CLI when the option is passed. + var noColorDiscarded bool + globalGroup := &serpent.Group{ Name: "Global", Description: `Global options are applied to all commands. They can be set using environment variables or flags.`, @@ -464,9 +471,10 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err { Flag: cliui.NoColorFlag, Env: "CODER_NO_COLOR", + Default: "false", Description: "Disable use of color in CLI output.", - Value: serpent.BoolOf(&cliui.NoColor), Group: globalGroup, + Value: serpent.BoolOf(&noColorDiscarded), }, { Flag: "version", diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index 66779a0e2fe6a..67fe85f4fff6e 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -89,7 +89,7 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. - --no-color bool + --no-color bool, $CODER_NO_COLOR (default: false) Disable use of color in CLI output. --no-feature-warning bool, $CODER_NO_FEATURE_WARNING diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index b477f91d893f5..e1cbf9be64557 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -38,11 +38,13 @@ func main() { }, } + var noColorDiscarded bool + root.Options = []serpent.Option{ { Default: "false", Flag: cliui.NoColorFlag, - Value: serpent.BoolOf(&cliui.NoColor), + Value: serpent.BoolOf(&noColorDiscarded), }, } diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden index a25de562d1625..8363d2a04b6ae 100644 --- a/enterprise/cli/testdata/coder_--help.golden +++ b/enterprise/cli/testdata/coder_--help.golden @@ -49,7 +49,7 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. - --no-color bool + --no-color bool, $CODER_NO_COLOR (default: false) Disable use of color in CLI output. --no-feature-warning bool, $CODER_NO_FEATURE_WARNING From 5e42118d6643ab94ef26d59d6c2b0e2f2ac50b7d Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 15:43:19 +0000 Subject: [PATCH 12/23] fix: run 'make gen' --- docs/reference/cli/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/reference/cli/README.md b/docs/reference/cli/README.md index cbe76991e4926..c5744a61af289 100644 --- a/docs/reference/cli/README.md +++ b/docs/reference/cli/README.md @@ -170,8 +170,10 @@ Path to the global `coder` config directory. ### --no-color -| | | -| ---- | ----------------- | -| Type | bool | +| | | +| ----------- | ---------------------------- | +| Type | bool | +| Environment | $CODER_NO_COLOR | +| Default | false | Disable use of color in CLI output. From 40eb24ee2b9888d3f6c28ce14491117f6b6eaf81 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 19:23:27 +0000 Subject: [PATCH 13/23] fix: refactor janky code --- cli/cliui/cliui.go | 68 ++++++++++++++++++---------------------------- cli/root.go | 23 +++++++++++----- cmd/cliui/main.go | 32 +++++++++++++++------- 3 files changed, 64 insertions(+), 59 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 2c8d87e62916b..16c69b57b86dd 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -2,10 +2,7 @@ package cliui import ( "flag" - "fmt" "os" - "slices" - "sync" "time" "github.com/muesli/termenv" @@ -36,46 +33,9 @@ type Styles struct { } var ( - color termenv.Profile - colorOnce sync.Once + color termenv.Profile ) -var ( - // ANSI color codes - red = Color("1") - green = Color("2") - yellow = Color("3") - magenta = Color("5") - white = Color("7") - brightBlue = Color("12") - brightMagenta = Color("13") -) - -// Color returns a color for the given string. -func Color(s string) termenv.Color { - colorOnce.Do(func() { - color = termenv.NewOutput(os.Stdout).ColorProfile() - - if flag.Lookup("test.v") != nil { - // Use a consistent colorless profile in tests so that results - // are deterministic. - color = termenv.Ascii - } - - // Currently it appears there is no way to use the flag from - // serpent as it isn't possible to create a root middleware that - // runs for every command. For now we just check if `os.Args` - // has the flag. - if slices.Contains(os.Args, fmt.Sprintf("--%s", NoColorFlag)) || - slices.Contains(os.Args, fmt.Sprintf("--%s=true", NoColorFlag)) || - os.Getenv("CODER_NO_COLOR") != "" || - os.Getenv("NO_COLOR") != "" { - color = termenv.Ascii - } - }) - return color.Color(s) -} - func isTerm() bool { return color != termenv.Ascii } @@ -135,7 +95,31 @@ func ifTerm(f pretty.Formatter) pretty.Formatter { return f } -func init() { +type InitOptions struct { + NoColor bool +} + +func Init(opts InitOptions) { + color = termenv.NewOutput(os.Stdout).ColorProfile() + + if flag.Lookup("test.v") != nil { + // Use a consistent colorless profile in tests so that results + // are deterministic. + color = termenv.Ascii + } + + if opts.NoColor { + color = termenv.Ascii + } + + red := color.Color("1") + green := color.Color("2") + yellow := color.Color("3") + magenta := color.Color("5") + white := color.Color("7") + brightBlue := color.Color("12") + brightMagenta := color.Color("13") + // We do not adapt the color based on whether the terminal is light or dark. // Doing so would require a round-trip between the program and the terminal // due to the OSC query and response. diff --git a/cli/root.go b/cli/root.go index 74956b5d5abd9..edaaae759da10 100644 --- a/cli/root.go +++ b/cli/root.go @@ -331,12 +331,21 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err r.clientURL = new(url.URL) } - // NOTE(Danielle): It appears there is no way to have a 'global' middleware in - // serpent so we manually handle the ENV/flag lookup and setup - // the option in the below OptionSet so it is documented. - // We use (and discard) this local variable to get the correct - // behavior from the CLI when the option is passed. - var noColorDiscarded bool + // Add a wrapper to every command to ensure we've loaded our CLI theme prior + // to running any handler. + var noColor bool + cmd.Walk(func(c *serpent.Command) { + middleware := func(next serpent.HandlerFunc) serpent.HandlerFunc { + cliui.Init(cliui.InitOptions{NoColor: noColor}) + return next + } + + if c.Middleware != nil { + c.Middleware = serpent.Chain(c.Middleware, middleware) + } else { + c.Middleware = middleware + } + }) globalGroup := &serpent.Group{ Name: "Global", @@ -474,7 +483,7 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err Default: "false", Description: "Disable use of color in CLI output.", Group: globalGroup, - Value: serpent.BoolOf(&noColorDiscarded), + Value: serpent.BoolOf(&noColor), }, { Flag: "version", diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index e1cbf9be64557..e02ecb7b71d2d 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -38,16 +38,6 @@ func main() { }, } - var noColorDiscarded bool - - root.Options = []serpent.Option{ - { - Default: "false", - Flag: cliui.NoColorFlag, - Value: serpent.BoolOf(&noColorDiscarded), - }, - } - root.Children = append(root.Children, &serpent.Command{ Use: "colors", Handler: func(inv *serpent.Invocation) error { @@ -398,6 +388,28 @@ func main() { }, }) + var noColor bool + root.Options = []serpent.Option{ + { + Default: "false", + Flag: cliui.NoColorFlag, + Value: serpent.BoolOf(&noColor), + }, + } + + root.Walk(func(cmd *serpent.Command) { + middleware := func(next serpent.HandlerFunc) serpent.HandlerFunc { + cliui.Init(cliui.InitOptions{NoColor: noColor}) + return next + } + + if cmd.Middleware != nil { + cmd.Middleware = serpent.Chain(cmd.Middleware, middleware) + } else { + cmd.Middleware = middleware + } + }) + err := root.Invoke(os.Args[1:]...).WithOS().Run() if err != nil { _, _ = fmt.Println(err.Error()) From ccf174a8183670e21f2b85a5b0522f25b5377f8f Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 19:33:40 +0000 Subject: [PATCH 14/23] fix: re-add public function --- cli/cliui/cliui.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 16c69b57b86dd..f0fcf463bd195 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -32,9 +32,12 @@ type Styles struct { Wrap pretty.Style } -var ( - color termenv.Profile -) +var color termenv.Profile + +// Color returns a color for the given string. +func Color(s string) termenv.Color { + return color.Color(s) +} func isTerm() bool { return color != termenv.Ascii From 1fbef1d1770099e50cbb1df697ad97d3fab9f67a Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 19:41:01 +0000 Subject: [PATCH 15/23] fix: re-add init for non-color tests --- cli/cliui/cliui.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index f0fcf463bd195..128e9dcc72b4b 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -102,7 +102,7 @@ type InitOptions struct { NoColor bool } -func Init(opts InitOptions) { +func init() { color = termenv.NewOutput(os.Stdout).ColorProfile() if flag.Lookup("test.v") != nil { @@ -110,7 +110,9 @@ func Init(opts InitOptions) { // are deterministic. color = termenv.Ascii } +} +func Init(opts InitOptions) { if opts.NoColor { color = termenv.Ascii } From 44c3726d42dd6b47f13555462e1c14d07316f3ef Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 19:47:32 +0000 Subject: [PATCH 16/23] fix: move styles to 'init' that can be --- cli/cliui/cliui.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 128e9dcc72b4b..e34d0aae7c26d 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -110,6 +110,20 @@ func init() { // are deterministic. color = termenv.Ascii } + + DefaultStyles.Code = pretty.Style{ + ifTerm(pretty.XPad(1, 1)), + pretty.FgColor(color.Color("#ED567A")), + pretty.BgColor(color.Color("#2C2C2C")), + } + DefaultStyles.Field = pretty.Style{ + pretty.XPad(1, 1), + pretty.FgColor(color.Color("#FFFFFF")), + pretty.BgColor(color.Color("#2B2A2A")), + } + DefaultStyles.Wrap = pretty.Style{ + pretty.LineWrap(80), + } } func Init(opts InitOptions) { @@ -129,22 +143,12 @@ func Init(opts InitOptions) { // Doing so would require a round-trip between the program and the terminal // due to the OSC query and response. DefaultStyles = Styles{ - Code: pretty.Style{ - ifTerm(pretty.XPad(1, 1)), - pretty.FgColor(color.Color("#ED567A")), - pretty.BgColor(color.Color("#2C2C2C")), - }, DateTimeStamp: pretty.Style{ pretty.FgColor(brightBlue), }, Error: pretty.Style{ pretty.FgColor(red), }, - Field: pretty.Style{ - pretty.XPad(1, 1), - pretty.FgColor(color.Color("#FFFFFF")), - pretty.BgColor(color.Color("#2B2A2A")), - }, Fuchsia: pretty.Style{ pretty.FgColor(brightMagenta), }, @@ -166,9 +170,6 @@ func Init(opts InitOptions) { Warn: pretty.Style{ pretty.FgColor(yellow), }, - Wrap: pretty.Style{ - pretty.LineWrap(80), - }, } } From d16f62555025b9fcacea2d497d70a3cd6f0390b0 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 19:57:48 +0000 Subject: [PATCH 17/23] fix: stop overwriting entire DefaultStyles --- cli/cliui/cliui.go | 54 ++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index e34d0aae7c26d..2ff91883d1446 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -142,34 +142,32 @@ func Init(opts InitOptions) { // We do not adapt the color based on whether the terminal is light or dark. // Doing so would require a round-trip between the program and the terminal // due to the OSC query and response. - DefaultStyles = Styles{ - DateTimeStamp: pretty.Style{ - pretty.FgColor(brightBlue), - }, - Error: pretty.Style{ - pretty.FgColor(red), - }, - Fuchsia: pretty.Style{ - pretty.FgColor(brightMagenta), - }, - FocusedPrompt: pretty.Style{ - pretty.FgColor(white), - pretty.Wrap("> ", ""), - pretty.FgColor(brightBlue), - }, - Keyword: pretty.Style{ - pretty.FgColor(green), - }, - Placeholder: pretty.Style{ - pretty.FgColor(magenta), - }, - Prompt: pretty.Style{ - pretty.FgColor(white), - pretty.Wrap(" ", ""), - }, - Warn: pretty.Style{ - pretty.FgColor(yellow), - }, + DefaultStyles.DateTimeStamp = pretty.Style{ + pretty.FgColor(brightBlue), + } + DefaultStyles.Error = pretty.Style{ + pretty.FgColor(red), + } + DefaultStyles.Fuchsia = pretty.Style{ + pretty.FgColor(brightMagenta), + } + DefaultStyles.FocusedPrompt = pretty.Style{ + pretty.FgColor(white), + pretty.Wrap("> ", ""), + pretty.FgColor(brightBlue), + } + DefaultStyles.Keyword = pretty.Style{ + pretty.FgColor(green), + } + DefaultStyles.Placeholder = pretty.Style{ + pretty.FgColor(magenta), + } + DefaultStyles.Prompt = pretty.Style{ + pretty.FgColor(white), + pretty.Wrap(" ", ""), + } + DefaultStyles.Warn = pretty.Style{ + pretty.FgColor(yellow), } } From 1babe9662ec82e402b8f1b54b1d559124eda0d19 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 20:06:53 +0000 Subject: [PATCH 18/23] fix: make code and field obey --no-color --- cli/cliui/cliui.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 2ff91883d1446..5efbebbba282f 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -113,13 +113,9 @@ func init() { DefaultStyles.Code = pretty.Style{ ifTerm(pretty.XPad(1, 1)), - pretty.FgColor(color.Color("#ED567A")), - pretty.BgColor(color.Color("#2C2C2C")), } DefaultStyles.Field = pretty.Style{ pretty.XPad(1, 1), - pretty.FgColor(color.Color("#FFFFFF")), - pretty.BgColor(color.Color("#2B2A2A")), } DefaultStyles.Wrap = pretty.Style{ pretty.LineWrap(80), @@ -142,12 +138,20 @@ func Init(opts InitOptions) { // We do not adapt the color based on whether the terminal is light or dark. // Doing so would require a round-trip between the program and the terminal // due to the OSC query and response. + DefaultStyles.Code = append(DefaultStyles.Code, + pretty.FgColor(color.Color("#ED567A")), + pretty.BgColor(color.Color("#2C2C2C")), + ) DefaultStyles.DateTimeStamp = pretty.Style{ pretty.FgColor(brightBlue), } DefaultStyles.Error = pretty.Style{ pretty.FgColor(red), } + DefaultStyles.Field = append(DefaultStyles.Field, + pretty.FgColor(color.Color("#FFFFFF")), + pretty.BgColor(color.Color("#2B2A2A")), + ) DefaultStyles.Fuchsia = pretty.Style{ pretty.FgColor(brightMagenta), } From ff3c39294d72475b0f0ed025ecce43c745faef1f Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 21:26:05 +0000 Subject: [PATCH 19/23] fix: rip out '--no-color' due to race condition We still support `NO_COLOR` env variable through termenv's `EnvColorProfile`. The reason for the race condition is that `DefaultStyles` is a global that we shouldn't mutate after `init` is called, but we have to mutate it after `init` has ran to have serpent collect the cli flags and env vars for us. --- cli/cliui/cliui.go | 142 +++++++++----------- cli/root.go | 24 ---- cli/testdata/coder_--help.golden | 3 - cmd/cliui/main.go | 22 --- docs/reference/cli/README.md | 10 -- enterprise/cli/testdata/coder_--help.golden | 3 - 6 files changed, 67 insertions(+), 137 deletions(-) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 5efbebbba282f..05bda4d7f1437 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -3,6 +3,7 @@ package cliui import ( "flag" "os" + "sync" "time" "github.com/muesli/termenv" @@ -11,8 +12,6 @@ import ( "github.com/coder/pretty" ) -const NoColorFlag = "no-color" - var Canceled = xerrors.New("canceled") // DefaultStyles compose visual elements of the UI. @@ -32,10 +31,32 @@ type Styles struct { Wrap pretty.Style } -var color termenv.Profile +var ( + color termenv.Profile + colorOnce sync.Once +) + +var ( + red = Color("1") + green = Color("2") + yellow = Color("3") + magenta = Color("5") + white = Color("7") + brightBlue = Color("12") + brightMagenta = Color("13") +) // Color returns a color for the given string. func Color(s string) termenv.Color { + colorOnce.Do(func() { + color = termenv.NewOutput(os.Stdout).EnvColorProfile() + + if flag.Lookup("test.v") != nil { + // Use a consistent colorless profile in tests so that results + // are deterministic. + color = termenv.Ascii + } + }) return color.Color(s) } @@ -91,87 +112,58 @@ func Field(s string) string { return pretty.Sprint(DefaultStyles.Field, s) } -func ifTerm(f pretty.Formatter) pretty.Formatter { +func ifTerm(fmt pretty.Formatter) pretty.Formatter { if !isTerm() { return pretty.Nop } - return f -} - -type InitOptions struct { - NoColor bool + return fmt } func init() { - color = termenv.NewOutput(os.Stdout).ColorProfile() - - if flag.Lookup("test.v") != nil { - // Use a consistent colorless profile in tests so that results - // are deterministic. - color = termenv.Ascii - } - - DefaultStyles.Code = pretty.Style{ - ifTerm(pretty.XPad(1, 1)), - } - DefaultStyles.Field = pretty.Style{ - pretty.XPad(1, 1), - } - DefaultStyles.Wrap = pretty.Style{ - pretty.LineWrap(80), - } -} - -func Init(opts InitOptions) { - if opts.NoColor { - color = termenv.Ascii - } - - red := color.Color("1") - green := color.Color("2") - yellow := color.Color("3") - magenta := color.Color("5") - white := color.Color("7") - brightBlue := color.Color("12") - brightMagenta := color.Color("13") - // We do not adapt the color based on whether the terminal is light or dark. // Doing so would require a round-trip between the program and the terminal // due to the OSC query and response. - DefaultStyles.Code = append(DefaultStyles.Code, - pretty.FgColor(color.Color("#ED567A")), - pretty.BgColor(color.Color("#2C2C2C")), - ) - DefaultStyles.DateTimeStamp = pretty.Style{ - pretty.FgColor(brightBlue), - } - DefaultStyles.Error = pretty.Style{ - pretty.FgColor(red), - } - DefaultStyles.Field = append(DefaultStyles.Field, - pretty.FgColor(color.Color("#FFFFFF")), - pretty.BgColor(color.Color("#2B2A2A")), - ) - DefaultStyles.Fuchsia = pretty.Style{ - pretty.FgColor(brightMagenta), - } - DefaultStyles.FocusedPrompt = pretty.Style{ - pretty.FgColor(white), - pretty.Wrap("> ", ""), - pretty.FgColor(brightBlue), - } - DefaultStyles.Keyword = pretty.Style{ - pretty.FgColor(green), - } - DefaultStyles.Placeholder = pretty.Style{ - pretty.FgColor(magenta), - } - DefaultStyles.Prompt = pretty.Style{ - pretty.FgColor(white), - pretty.Wrap(" ", ""), - } - DefaultStyles.Warn = pretty.Style{ - pretty.FgColor(yellow), + DefaultStyles = Styles{ + Code: pretty.Style{ + ifTerm(pretty.XPad(1, 1)), + pretty.FgColor(Color("#ED567A")), + pretty.BgColor(Color("#2C2C2C")), + }, + DateTimeStamp: pretty.Style{ + pretty.FgColor(brightBlue), + }, + Error: pretty.Style{ + pretty.FgColor(red), + }, + Field: pretty.Style{ + pretty.XPad(1, 1), + pretty.FgColor(Color("#FFFFFF")), + pretty.BgColor(Color("#2B2A2A")), + }, + Fuchsia: pretty.Style{ + pretty.FgColor(brightMagenta), + }, + FocusedPrompt: pretty.Style{ + pretty.FgColor(white), + pretty.Wrap("> ", ""), + pretty.FgColor(brightBlue), + }, + Keyword: pretty.Style{ + pretty.FgColor(green), + }, + Placeholder: pretty.Style{ + pretty.FgColor(magenta), + }, + Prompt: pretty.Style{ + pretty.FgColor(white), + pretty.Wrap(" ", ""), + }, + Warn: pretty.Style{ + pretty.FgColor(yellow), + }, + Wrap: pretty.Style{ + pretty.LineWrap(80), + }, } } diff --git a/cli/root.go b/cli/root.go index edaaae759da10..4945ecdd1656c 100644 --- a/cli/root.go +++ b/cli/root.go @@ -331,22 +331,6 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err r.clientURL = new(url.URL) } - // Add a wrapper to every command to ensure we've loaded our CLI theme prior - // to running any handler. - var noColor bool - cmd.Walk(func(c *serpent.Command) { - middleware := func(next serpent.HandlerFunc) serpent.HandlerFunc { - cliui.Init(cliui.InitOptions{NoColor: noColor}) - return next - } - - if c.Middleware != nil { - c.Middleware = serpent.Chain(c.Middleware, middleware) - } else { - c.Middleware = middleware - } - }) - globalGroup := &serpent.Group{ Name: "Global", Description: `Global options are applied to all commands. They can be set using environment variables or flags.`, @@ -477,14 +461,6 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err Value: serpent.StringOf(&r.globalConfig), Group: globalGroup, }, - { - Flag: cliui.NoColorFlag, - Env: "CODER_NO_COLOR", - Default: "false", - Description: "Disable use of color in CLI output.", - Group: globalGroup, - Value: serpent.BoolOf(&noColor), - }, { Flag: "version", // This was requested by a customer to assist with their migration. diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index 67fe85f4fff6e..2ebbc458e1b6b 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -89,9 +89,6 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. - --no-color bool, $CODER_NO_COLOR (default: false) - Disable use of color in CLI output. - --no-feature-warning bool, $CODER_NO_FEATURE_WARNING Suppress warnings about unlicensed features. diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index e02ecb7b71d2d..2a079ece4be38 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -388,28 +388,6 @@ func main() { }, }) - var noColor bool - root.Options = []serpent.Option{ - { - Default: "false", - Flag: cliui.NoColorFlag, - Value: serpent.BoolOf(&noColor), - }, - } - - root.Walk(func(cmd *serpent.Command) { - middleware := func(next serpent.HandlerFunc) serpent.HandlerFunc { - cliui.Init(cliui.InitOptions{NoColor: noColor}) - return next - } - - if cmd.Middleware != nil { - cmd.Middleware = serpent.Chain(cmd.Middleware, middleware) - } else { - cmd.Middleware = middleware - } - }) - err := root.Invoke(os.Args[1:]...).WithOS().Run() if err != nil { _, _ = fmt.Println(err.Error()) diff --git a/docs/reference/cli/README.md b/docs/reference/cli/README.md index c5744a61af289..0b0331afa8273 100644 --- a/docs/reference/cli/README.md +++ b/docs/reference/cli/README.md @@ -167,13 +167,3 @@ Disable network telemetry. Network telemetry is collected when connecting to wor | Default | ~/.config/coderv2 | Path to the global `coder` config directory. - -### --no-color - -| | | -| ----------- | ---------------------------- | -| Type | bool | -| Environment | $CODER_NO_COLOR | -| Default | false | - -Disable use of color in CLI output. diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden index 8363d2a04b6ae..e575451922a5b 100644 --- a/enterprise/cli/testdata/coder_--help.golden +++ b/enterprise/cli/testdata/coder_--help.golden @@ -49,9 +49,6 @@ variables or flags. requests. The command must output each header as `key=value` on its own line. - --no-color bool, $CODER_NO_COLOR (default: false) - Disable use of color in CLI output. - --no-feature-warning bool, $CODER_NO_FEATURE_WARNING Suppress warnings about unlicensed features. From 6d93c563208fefc7179db8a2f09af74bed32a7d2 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 13 Sep 2024 21:35:42 +0000 Subject: [PATCH 20/23] fix: apply nit --- cli/cliui/cliui.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 05bda4d7f1437..9b2189e96bbde 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -37,6 +37,7 @@ var ( ) var ( + // ANSI color codes red = Color("1") green = Color("2") yellow = Color("3") From 506aa284d2a23b73c4310e348a897d8525a72171 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 16 Sep 2024 18:58:10 +0000 Subject: [PATCH 21/23] fix: simplify code && hide command --- cmd/cliui/main.go | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 2a079ece4be38..eb9945585ec94 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -39,38 +39,19 @@ func main() { } root.Children = append(root.Children, &serpent.Command{ - Use: "colors", + Use: "colors", + Hidden: true, Handler: func(inv *serpent.Invocation) error { - msg := pretty.Sprint(cliui.DefaultStyles.Code, "This is a code message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Error, "This is an error message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Field, "This is a field message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Keyword, "This is a keyword message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Placeholder, "This is a placeholder message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Prompt, "This is a prompt message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Fuchsia, "This is a fuchsia message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - - msg = pretty.Sprint(cliui.DefaultStyles.Warn, "This is a warning message") - _, _ = fmt.Fprintln(inv.Stdout, msg) - + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Code, "This is a code message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Error, "This is an error message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Field, "This is a field message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Keyword, "This is a keyword message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Placeholder, "This is a placeholder message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Prompt, "This is a prompt message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Fuchsia, "This is a fuchsia message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Warn, "This is a warning message\n") return nil }, }) From 997dc43707e9ecfceb971745f2dadb14b7c1cf85 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 16 Sep 2024 18:59:39 +0000 Subject: [PATCH 22/23] fix: newline shouldn't be themed --- cmd/cliui/main.go | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index eb9945585ec94..8d8cca1f39dcc 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -42,16 +42,36 @@ func main() { Use: "colors", Hidden: true, Handler: func(inv *serpent.Invocation) error { - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Code, "This is a code message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Error, "This is an error message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Field, "This is a field message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Keyword, "This is a keyword message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Placeholder, "This is a placeholder message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Prompt, "This is a prompt message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Fuchsia, "This is a fuchsia message\n") - pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Warn, "This is a warning message\n") + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Code, "This is a code message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Error, "This is an error message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Field, "This is a field message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Keyword, "This is a keyword message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Placeholder, "This is a placeholder message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Prompt, "This is a prompt message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Fuchsia, "This is a fuchsia message") + fmt.Fprintln(inv.Stdout) + + pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Warn, "This is a warning message") + fmt.Fprintln(inv.Stdout) + return nil }, }) From 24a838d4122cfab8e44a2d89c2cf2dc137f841be Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 16 Sep 2024 19:03:22 +0000 Subject: [PATCH 23/23] fix: appease the linter --- cmd/cliui/main.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 8d8cca1f39dcc..da7f75f5cfd18 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -43,34 +43,34 @@ func main() { Hidden: true, Handler: func(inv *serpent.Invocation) error { pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Code, "This is a code message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.DateTimeStamp, "This is a datetimestamp message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Error, "This is an error message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Field, "This is a field message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Keyword, "This is a keyword message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Placeholder, "This is a placeholder message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Prompt, "This is a prompt message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.FocusedPrompt, "This is a focused prompt message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Fuchsia, "This is a fuchsia message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) pretty.Fprintf(inv.Stdout, cliui.DefaultStyles.Warn, "This is a warning message") - fmt.Fprintln(inv.Stdout) + _, _ = fmt.Fprintln(inv.Stdout) return nil },