more color, less env vars
This commit is contained in:
parent
5c37bbb9f8
commit
6ec1c56f0f
|
@ -26,7 +26,11 @@ func cobraCommandFullName(c *cobra.Command) []string {
|
||||||
var Help = &cobra.Command{
|
var Help = &cobra.Command{
|
||||||
Use: _c.HelpCommandName + " [command]",
|
Use: _c.HelpCommandName + " [command]",
|
||||||
Short: "Display usage information for any 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) {
|
ValidArgsFunction: func(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
var completions []string
|
var completions []string
|
||||||
cmd, _, e := c.Root().Find(args)
|
cmd, _, e := c.Root().Find(args)
|
||||||
|
@ -47,6 +51,7 @@ var Help = &cobra.Command{
|
||||||
return completions, cobra.ShellCompDirectiveNoFileComp
|
return completions, cobra.ShellCompDirectiveNoFileComp
|
||||||
},
|
},
|
||||||
Run: func(c *cobra.Command, args []string) {
|
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] {
|
if len(args) > 0 && c != nil && c.Name() != args[len(args)-1] {
|
||||||
c, topicArgs, err := c.Root().Find(args)
|
c, topicArgs, err := c.Root().Find(args)
|
||||||
if err == nil && c != nil && len(topicArgs) == 0 {
|
if err == nil && c != nil && len(topicArgs) == 0 {
|
||||||
|
|
|
@ -7,7 +7,10 @@ import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HelpCommandName sets the name for the command that offers help.
|
||||||
const HelpCommandName = "help"
|
const HelpCommandName = "help"
|
||||||
|
|
||||||
|
// HelpTemplate is the markdown template to use when rendering help.
|
||||||
|
//
|
||||||
//go:embed help.md
|
//go:embed help.md
|
||||||
var HelpTemplate string
|
var HelpTemplate string
|
||||||
|
|
|
@ -12,10 +12,14 @@ description: {{ .Command.Short }}
|
||||||
|
|
||||||
`{{ replace .Command.UseLine " [flags]" "" }}{{if .Command.HasAvailableSubCommands}} SUBCOMMAND{{end}}`
|
`{{ replace .Command.UseLine " [flags]" "" }}{{if .Command.HasAvailableSubCommands}} SUBCOMMAND{{end}}`
|
||||||
|
|
||||||
{{ if and .Spec.IsRoot (not (eq .Command.Name "help")) }}
|
{{ if .Spec.IsRoot }}
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
{{ if eq .Command.Name "help" -}}
|
||||||
|
{{ .Command.Long }}
|
||||||
|
{{- else -}}
|
||||||
{{ .Spec.Description }}
|
{{ .Spec.Description }}
|
||||||
|
{{- end }}
|
||||||
{{- if .Spec.HasAdditionalHelp }}
|
{{- if .Spec.HasAdditionalHelp }}
|
||||||
{{ .Spec.AdditionalHelp .HTMLOutput }}
|
{{ .Spec.AdditionalHelp .HTMLOutput }}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
|
|
@ -47,28 +47,18 @@ func (cmd *Command) HelpRenderer(globalOptions Options) func(cc *cobra.Command,
|
||||||
|
|
||||||
func (cmd *Command) ShowHelp(globalOptions Options, args []string) ([]byte, error) {
|
func (cmd *Command) ShowHelp(globalOptions Options, args []string) ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
colorEnabled := runtime.ColorEnabled()
|
||||||
c := &combinedCommand{
|
c := &combinedCommand{
|
||||||
Spec: cmd,
|
Spec: cmd,
|
||||||
Command: cmd.Cobra,
|
Command: cmd.Cobra,
|
||||||
GlobalOptions: globalOptions,
|
GlobalOptions: globalOptions,
|
||||||
HTMLOutput: runtime.UnstyledHelpEnabled(),
|
HTMLOutput: runtime.HelpStyle() == "markdown",
|
||||||
}
|
}
|
||||||
err := render.HelpTemplate(runtime.Executable).Execute(&buf, c)
|
err := render.HelpTemplate(runtime.Executable).Execute(&buf, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
content, err := render.Markdown(buf.Bytes(), colorEnabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -11,7 +11,6 @@ Package env holds environment variable names that are meant to be overridden by
|
||||||
import "git.rob.mx/nidito/chinampa/env"
|
import "git.rob.mx/nidito/chinampa/env"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
env.HelpUnstyled = "MY_APP_PLAIN_HELP"
|
|
||||||
env.HelpStyle = "MY_APP_HELP_STYLE"
|
env.HelpStyle = "MY_APP_HELP_STYLE"
|
||||||
env.Verbose = "MY_APP_VERBOSE"
|
env.Verbose = "MY_APP_VERBOSE"
|
||||||
env.Silent = "MY_APP_SILENT"
|
env.Silent = "MY_APP_SILENT"
|
||||||
|
@ -20,9 +19,6 @@ Package env holds environment variable names that are meant to be overridden by
|
||||||
*/
|
*/
|
||||||
package env
|
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.
|
// HelpStyle identifies the theme to use for help formatting.
|
||||||
var HelpStyle = "HELP_STYLE"
|
var HelpStyle = "HELP_STYLE"
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
_c "git.rob.mx/nidito/chinampa/internal/constants"
|
_c "git.rob.mx/nidito/chinampa/internal/constants"
|
||||||
"git.rob.mx/nidito/chinampa/pkg/env"
|
"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/charmbracelet/glamour"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
@ -23,10 +23,34 @@ func addBackticks(str []byte) []byte {
|
||||||
// Markdown renders markdown-formatted content to the tty.
|
// Markdown renders markdown-formatted content to the tty.
|
||||||
func Markdown(content []byte, withColor bool) ([]byte, error) {
|
func Markdown(content []byte, withColor bool) ([]byte, error) {
|
||||||
content = addBackticks(content)
|
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
|
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)
|
width, _, err := term.GetSize(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,22 +58,6 @@ func Markdown(content []byte, withColor bool) ([]byte, error) {
|
||||||
width = 80
|
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(
|
renderer, err := glamour.NewTermRenderer(
|
||||||
styleFunc,
|
styleFunc,
|
||||||
glamour.WithEmoji(),
|
glamour.WithEmoji(),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
func TestMarkdownUnstyled(t *testing.T) {
|
func TestMarkdownUnstyled(t *testing.T) {
|
||||||
content := []byte("# hello")
|
content := []byte("# hello")
|
||||||
os.Setenv(env.HelpUnstyled, "true")
|
os.Setenv(env.HelpStyle, "markdown")
|
||||||
res, err := render.Markdown(content, false)
|
res, err := render.Markdown(content, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,7 +28,7 @@ func TestMarkdownUnstyled(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarkdownNoColor(t *testing.T) {
|
func TestMarkdownNoColor(t *testing.T) {
|
||||||
os.Unsetenv(env.HelpUnstyled)
|
os.Unsetenv(env.HelpStyle)
|
||||||
content := []byte("# hello ﹅world﹅")
|
content := []byte("# hello ﹅world﹅")
|
||||||
res, err := render.Markdown(content, false)
|
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"
|
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) {
|
func TestMarkdownColor(t *testing.T) {
|
||||||
os.Unsetenv(env.HelpUnstyled)
|
os.Unsetenv(env.HelpStyle)
|
||||||
content := []byte("# hello")
|
content := []byte("# hello")
|
||||||
|
|
||||||
styles := map[string][]byte{
|
styles := map[string][]byte{
|
||||||
|
|
|
@ -9,6 +9,7 @@ package runtime
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.rob.mx/nidito/chinampa/pkg/env"
|
"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
|
// 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.
|
// HelpStyle returns the style to use when rendering help.
|
||||||
func UnstyledHelpEnabled() bool {
|
func HelpStyle() string {
|
||||||
return isTrueIsh(os.Getenv(env.HelpUnstyled))
|
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`.
|
// EnvironmentMap returns a map of environment keys for color, debugging and verbosity and their values, ready for `os.Setenv`.
|
||||||
|
|
|
@ -172,20 +172,11 @@ func TestEnabled(t *testing.T) {
|
||||||
Name: env.NoColor,
|
Name: env.NoColor,
|
||||||
Func: ColorEnabled,
|
Func: ColorEnabled,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: env.HelpUnstyled,
|
|
||||||
Func: ColorEnabled,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: env.Debug,
|
Name: env.Debug,
|
||||||
Func: DebugEnabled,
|
Func: DebugEnabled,
|
||||||
Expects: true,
|
Expects: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: env.HelpUnstyled,
|
|
||||||
Func: UnstyledHelpEnabled,
|
|
||||||
Expects: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
|
|
Loading…
Reference in New Issue