From 0776673c7bad90d68b5d2a0e58a7da4ccde1cd86 Mon Sep 17 00:00:00 2001 From: Craig Gumbley Date: Wed, 18 May 2022 17:31:46 +0100 Subject: [PATCH] Colorize config output This commit adds optional colorization of the config output. In certain situations this can make reading configuration easier and it also looks pretty neat. There is also an optional --no-color flag that can be passed. This will disable set the chroma formatter to `noop` rather than terminal16m. Currently, the data is still tokenized by chroma but not formatted so it does not print with any ascii codes. In this implementation it doesn't matter too much because the size of the configuration will always been small so there are no major tradeoffs.. an improved solution could be to skip passing through chroma if the --no-color flag is passed! --- cmd/config.go | 10 ++- go.mod | 2 +- internal/pkg/configuration/configuration.go | 65 +++++++++++++++++-- .../pkg/configuration/configuration_test.go | 7 +- 4 files changed, 70 insertions(+), 14 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index 90e9139..c87b8ed 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -10,7 +10,10 @@ import ( "github.com/spf13/cobra" ) -var output string +var ( + output string + noColor bool +) // configCmd is the entry point for printing the applications configuration in the terminal var configCmd = &cobra.Command{ @@ -20,9 +23,9 @@ var configCmd = &cobra.Command{ RunE: func(command *cobra.Command, args []string) error { switch output { case "json": - return configuration.Config.PrintJSON(os.Stdout) + return configuration.Config.PrintJSON(noColor, os.Stdout) case "yaml": - return configuration.Config.PrintYAML(os.Stdout) + return configuration.Config.PrintYAML(noColor, os.Stdout) default: return errors.New("invalid output format. Valid values are 'json' and 'yaml'") } @@ -31,4 +34,5 @@ var configCmd = &cobra.Command{ func init() { configCmd.Flags().StringVarP(&output, "output", "o", "yaml", "The output format. Valid values are 'json' and 'yaml'. Defaults to 'yaml'.") + configCmd.Flags().BoolVarP(&noColor, "no-color", "n", false, "Disable color output") } diff --git a/go.mod b/go.mod index d430b2f..12185f5 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/Masterminds/semver/v3 v3.1.1 + github.com/alecthomas/chroma v0.10.0 github.com/briandowns/spinner v1.18.1 github.com/charmbracelet/bubbles v0.10.3 github.com/charmbracelet/bubbletea v0.20.0 @@ -21,7 +22,6 @@ require ( ) require ( - github.com/alecthomas/chroma v0.10.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/cli/safeexec v1.0.0 // indirect github.com/cli/shurcooL-graphql v0.0.1 // indirect diff --git a/internal/pkg/configuration/configuration.go b/internal/pkg/configuration/configuration.go index 982071d..be034e6 100644 --- a/internal/pkg/configuration/configuration.go +++ b/internal/pkg/configuration/configuration.go @@ -13,6 +13,10 @@ import ( "os" "path/filepath" + "github.com/alecthomas/chroma" + "github.com/alecthomas/chroma/formatters" + "github.com/alecthomas/chroma/lexers" + "github.com/alecthomas/chroma/styles" "github.com/spf13/viper" "gopkg.in/yaml.v2" ) @@ -28,28 +32,73 @@ type configuration struct { CheckForUpdates bool `mapstructure:"check_for_updates" yaml:"check_for_updates" json:"checkForUpdates"` } -func write(data []byte, writer io.Writer) error { - _, err := fmt.Fprint(writer, string(data)) - return err +type writeOptions struct { + data string + lexerName string + noColor bool + writer io.Writer } -func (c *configuration) PrintJSON(writer io.Writer) error { +func prettyWrite(opts writeOptions) error { + lexer := lexers.Get(opts.lexerName) + if lexer == nil { + lexer = lexers.Fallback + } + + lexer = chroma.Coalesce(lexer) + + style := styles.Get("native") + if style == nil { + style = styles.Fallback + } + + formatter := formatters.Get("terminal16m") + + if opts.noColor { + formatter = formatters.Get("noop") + } + + iterator, err := lexer.Tokenise(nil, opts.data) + if err != nil { + return err + } + + return formatter.Format(opts.writer, style, iterator) +} + +func (c *configuration) PrintJSON(noColor bool, writer io.Writer) error { b, err := json.MarshalIndent(c, "", " ") b = append(b, '\n') if err != nil { return err } - return write(b, writer) + opts := writeOptions{ + data: string(b), + lexerName: "json", + noColor: noColor, + writer: writer, + } + + return prettyWrite(opts) } -func (c *configuration) PrintYAML(writer io.Writer) error { +func (c *configuration) PrintYAML(noColor bool, writer io.Writer) error { b, err := yaml.Marshal(c) + y := []byte("---\n") + y = append(y, b...) if err != nil { return err } - return write(b, writer) + opts := writeOptions{ + data: string(y), + lexerName: "json", + noColor: noColor, + writer: writer, + } + + return prettyWrite(opts) } func InitConfig() error { @@ -103,4 +152,6 @@ func setDefaults() { viper.SetDefault("show_unreleased", true) viper.SetDefault("check_for_updates", true) + + viper.SetDefault("no_color", false) } diff --git a/internal/pkg/configuration/configuration_test.go b/internal/pkg/configuration/configuration_test.go index 96959f3..6f4a2bb 100644 --- a/internal/pkg/configuration/configuration_test.go +++ b/internal/pkg/configuration/configuration_test.go @@ -36,7 +36,7 @@ func TestPrintJSON(t *testing.T) { config := configuration.Config var buf bytes.Buffer - err = config.PrintJSON(&buf) + err = config.PrintJSON(true, &buf) assert.NoError(t, err) cfg := `{ @@ -73,10 +73,11 @@ func TestPrintYAML(t *testing.T) { config := configuration.Config var buf bytes.Buffer - err = config.PrintYAML(&buf) + err = config.PrintYAML(true, &buf) assert.NoError(t, err) - cfg := `file_name: CHANGELOG.md + cfg := `--- +file_name: CHANGELOG.md excluded_labels: - maintenance sections: