more color, less env vars

This commit is contained in:
Roberto Hidalgo 2023-03-23 19:51:36 -06:00
parent 5c37bbb9f8
commit 6ec1c56f0f
9 changed files with 50 additions and 52 deletions

View File

@ -26,7 +26,11 @@ func cobraCommandFullName(c *cobra.Command) []string {
var Help = &cobra.Command{
Use: _c.HelpCommandName + " [command]",
Short: "Display usage information for any command",
Long: `Help provides the valid arguments and options for any command known to ` + runtime.Executable + `. By default, ﹅` + runtime.Executable + ` help﹅ will query the environment variable ﹅COLORFGBG﹅ to decide which style to use when rendering help, except if ﹅` + env.HelpUnstyled + `﹅ is set. Valid styles are: **light**, **dark**, and **auto**.`,
Long: `Help provides the valid arguments and options for any command known to @chinampa@.
## Colorized output
By default, and unless ` + env.NoColor + ` is set, @chinampa@ help will query the environment variable COLORFGBG to decide which style to use when rendering help, unless if ` + env.HelpStyle + ` is set to any of the following values: **light**, **dark**, **markdown**, and **auto**. 24-bit color is available when COLORTERM is set to truecolor.`,
ValidArgsFunction: func(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var completions []string
cmd, _, e := c.Root().Find(args)
@ -47,6 +51,7 @@ var Help = &cobra.Command{
return completions, cobra.ShellCompDirectiveNoFileComp
},
Run: func(c *cobra.Command, args []string) {
c.Long = strings.ReplaceAll(c.Long, "@chinampa@", runtime.Executable)
if len(args) > 0 && c != nil && c.Name() != args[len(args)-1] {
c, topicArgs, err := c.Root().Find(args)
if err == nil && c != nil && len(topicArgs) == 0 {

View File

@ -7,7 +7,10 @@ import (
_ "embed"
)
// HelpCommandName sets the name for the command that offers help.
const HelpCommandName = "help"
// HelpTemplate is the markdown template to use when rendering help.
//
//go:embed help.md
var HelpTemplate string

View File

@ -12,10 +12,14 @@ description: {{ .Command.Short }}
`{{ replace .Command.UseLine " [flags]" "" }}{{if .Command.HasAvailableSubCommands}} SUBCOMMAND{{end}}`
{{ if and .Spec.IsRoot (not (eq .Command.Name "help")) }}
{{ if .Spec.IsRoot }}
## Description
{{ if eq .Command.Name "help" -}}
{{ .Command.Long }}
{{- else -}}
{{ .Spec.Description }}
{{- end }}
{{- if .Spec.HasAdditionalHelp }}
{{ .Spec.AdditionalHelp .HTMLOutput }}
{{ end -}}

View File

@ -47,28 +47,18 @@ func (cmd *Command) HelpRenderer(globalOptions Options) func(cc *cobra.Command,
func (cmd *Command) ShowHelp(globalOptions Options, args []string) ([]byte, error) {
var buf bytes.Buffer
colorEnabled := runtime.ColorEnabled()
c := &combinedCommand{
Spec: cmd,
Command: cmd.Cobra,
GlobalOptions: globalOptions,
HTMLOutput: runtime.UnstyledHelpEnabled(),
HTMLOutput: runtime.HelpStyle() == "markdown",
}
err := render.HelpTemplate(runtime.Executable).Execute(&buf, c)
if err != nil {
return nil, err
}
colorEnabled := runtime.ColorEnabled()
flags := cmd.Cobra.Flags()
ncf := cmd.Cobra.Flag("no-color") // nolint:ifshort
cf := cmd.Cobra.Flag("color") // nolint:ifshort
if noColorFlag, err := flags.GetBool("no-color"); err == nil && ncf.Changed {
colorEnabled = !noColorFlag
} else if colorFlag, err := flags.GetBool("color"); err == nil && cf.Changed {
colorEnabled = colorFlag
}
content, err := render.Markdown(buf.Bytes(), colorEnabled)
if err != nil {
return nil, err

4
pkg/env/env.go vendored
View File

@ -11,7 +11,6 @@ Package env holds environment variable names that are meant to be overridden by
import "git.rob.mx/nidito/chinampa/env"
func init() {
env.HelpUnstyled = "MY_APP_PLAIN_HELP"
env.HelpStyle = "MY_APP_HELP_STYLE"
env.Verbose = "MY_APP_VERBOSE"
env.Silent = "MY_APP_SILENT"
@ -20,9 +19,6 @@ Package env holds environment variable names that are meant to be overridden by
*/
package env
// HelpUnstyled means help will not be colored nor formatted for a TTY.
var HelpUnstyled = "HELP_STYLE_PLAIN"
// HelpStyle identifies the theme to use for help formatting.
var HelpStyle = "HELP_STYLE"

View File

@ -10,7 +10,7 @@ import (
_c "git.rob.mx/nidito/chinampa/internal/constants"
"git.rob.mx/nidito/chinampa/pkg/env"
"git.rob.mx/nidito/chinampa/pkg/runtime"
"git.rob.mx/nidito/chinampa/pkg/logger"
"github.com/charmbracelet/glamour"
"github.com/sirupsen/logrus"
"golang.org/x/term"
@ -23,10 +23,34 @@ func addBackticks(str []byte) []byte {
// Markdown renders markdown-formatted content to the tty.
func Markdown(content []byte, withColor bool) ([]byte, error) {
content = addBackticks(content)
var styleFunc glamour.TermRendererOption
if runtime.UnstyledHelpEnabled() {
style := os.Getenv(env.HelpStyle)
if style == "markdown" {
// markdown will render frontmatter along content and will not format for
// tty readability
return content, nil
}
if withColor {
switch style {
case "dark":
// For color TTYs with light text on dark background
styleFunc = glamour.WithStandardStyle("dark")
case "light":
// For color TTYs with dark text on light background
styleFunc = glamour.WithStandardStyle("light")
default:
// Glamour selects a style for the user.
styleFunc = glamour.WithStandardStyle("auto")
if style != "" {
logger.Warnf("Unknown %s=%s, assuming \"auto\"", env.HelpStyle, style)
}
}
} else {
// basically the same as the "markdown" style, except formatted for
// tty redability, prettifying and indenting, while not adding color.
styleFunc = glamour.WithStandardStyle("notty")
}
width, _, err := term.GetSize(0)
if err != nil {
@ -34,22 +58,6 @@ func Markdown(content []byte, withColor bool) ([]byte, error) {
width = 80
}
var styleFunc glamour.TermRendererOption
if withColor {
style := os.Getenv(env.HelpStyle)
switch style {
case "dark":
styleFunc = glamour.WithStandardStyle("dark")
case "light":
styleFunc = glamour.WithStandardStyle("light")
default:
styleFunc = glamour.WithStandardStyle("auto")
}
} else {
styleFunc = glamour.WithStandardStyle("notty")
}
renderer, err := glamour.NewTermRenderer(
styleFunc,
glamour.WithEmoji(),

View File

@ -14,7 +14,7 @@ import (
func TestMarkdownUnstyled(t *testing.T) {
content := []byte("# hello")
os.Setenv(env.HelpUnstyled, "true")
os.Setenv(env.HelpStyle, "markdown")
res, err := render.Markdown(content, false)
if err != nil {
@ -28,7 +28,7 @@ func TestMarkdownUnstyled(t *testing.T) {
}
func TestMarkdownNoColor(t *testing.T) {
os.Unsetenv(env.HelpUnstyled)
os.Unsetenv(env.HelpStyle)
content := []byte("# hello ﹅world﹅")
res, err := render.Markdown(content, false)
@ -51,7 +51,7 @@ var autoStyleTestRender = "\n\x1b[38;5;228;48;5;63;1m\x1b[0m\x1b[38;5;228;48;5;6
const lightStyleTestRender = "\n\x1b[38;5;228;48;5;63;1m\x1b[0m\x1b[38;5;228;48;5;63;1m\x1b[0m \x1b[38;5;228;48;5;63;1m \x1b[0m\x1b[38;5;228;48;5;63;1mhello\x1b[0m\x1b[38;5;228;48;5;63;1m \x1b[0m\x1b[38;5;234m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[38;5;234m \x1b[0m\x1b[0m\n\x1b[0m\n"
func TestMarkdownColor(t *testing.T) {
os.Unsetenv(env.HelpUnstyled)
os.Unsetenv(env.HelpStyle)
content := []byte("# hello")
styles := map[string][]byte{

View File

@ -9,6 +9,7 @@ package runtime
import (
"os"
"strconv"
"strings"
"git.rob.mx/nidito/chinampa/pkg/env"
)
@ -129,12 +130,12 @@ func ColorEnabled() bool {
}
// we're talking to ttys, we want color unless NO_COLOR/--no-color
return !(isTrueIsh(os.Getenv(env.NoColor)) || UnstyledHelpEnabled() || flagInArgs("no-color"))
return !(isTrueIsh(os.Getenv(env.NoColor)) || flagInArgs("no-color"))
}
// UnstyledHelpEnabled tells if help should be printed without formatting.
func UnstyledHelpEnabled() bool {
return isTrueIsh(os.Getenv(env.HelpUnstyled))
// HelpStyle returns the style to use when rendering help.
func HelpStyle() string {
return strings.ToLower(os.Getenv(env.HelpStyle))
}
// EnvironmentMap returns a map of environment keys for color, debugging and verbosity and their values, ready for `os.Setenv`.

View File

@ -172,20 +172,11 @@ func TestEnabled(t *testing.T) {
Name: env.NoColor,
Func: ColorEnabled,
},
{
Name: env.HelpUnstyled,
Func: ColorEnabled,
},
{
Name: env.Debug,
Func: DebugEnabled,
Expects: true,
},
{
Name: env.HelpUnstyled,
Func: UnstyledHelpEnabled,
Expects: true,
},
}
for _, c := range cases {