Add "reference" help topic (#2223)
* Add "reference" help topic * Only print reference as a help topic * fix for color fns, slightly generalize * WIP for switching to markdown * escape gt/lt * minor * higher wrap point * detect terminal theme * futz with angle brackets once more * minor cleanup * prepend parent commands * rename help topic fns and add test * Simplify reference help generation - the `<...>` characters from command usage line are now preserved by enclosing the entire usage synopsis in a code span - hard breaks in flag usage lines are preserved by enclosing flag usage in a code block - TTY detection and Markdown rendering are now delayed until the user explicitly requests `gh help reference` - `gh help reference` output is now pager-enabled Co-authored-by: vilmibm <vilmibm@github.com> Co-authored-by: vilmibm <vilmibm@neongrid.space> Co-authored-by: Mislav Marohnić <mislav@github.com>
This commit is contained in:
parent
ee4827483d
commit
e87b5bcaff
5 changed files with 96 additions and 4 deletions
69
pkg/cmd/root/help_reference.go
Normal file
69
pkg/cmd/root/help_reference.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package root
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/cli/cli/pkg/iostreams"
|
||||
"github.com/cli/cli/pkg/markdown"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func referenceHelpFn(io *iostreams.IOStreams) func(*cobra.Command, []string) {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
wrapWidth := 0
|
||||
style := "notty"
|
||||
if io.IsStdoutTTY() {
|
||||
wrapWidth = io.TerminalWidth()
|
||||
style = markdown.GetStyle(io.DetectTerminalTheme())
|
||||
}
|
||||
|
||||
md, err := markdown.RenderWrap(cmd.Long, style, wrapWidth)
|
||||
if err != nil {
|
||||
fmt.Fprintln(io.ErrOut, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !io.IsStdoutTTY() {
|
||||
fmt.Fprint(io.Out, dedent(md))
|
||||
return
|
||||
}
|
||||
|
||||
_ = io.StartPager()
|
||||
defer io.StopPager()
|
||||
fmt.Fprint(io.Out, md)
|
||||
}
|
||||
}
|
||||
|
||||
func referenceLong(cmd *cobra.Command) string {
|
||||
buf := bytes.NewBufferString("# gh reference\n\n")
|
||||
for _, c := range cmd.Commands() {
|
||||
if c.Hidden {
|
||||
continue
|
||||
}
|
||||
cmdRef(buf, c, 2)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func cmdRef(w io.Writer, cmd *cobra.Command, depth int) {
|
||||
// Name + Description
|
||||
fmt.Fprintf(w, "%s `%s`\n\n", strings.Repeat("#", depth), cmd.UseLine())
|
||||
fmt.Fprintf(w, "%s\n\n", cmd.Short)
|
||||
|
||||
// Flags
|
||||
// TODO: fold in InheritedFlags/PersistentFlags, but omit `--help` due to repetitiveness
|
||||
if flagUsages := cmd.Flags().FlagUsages(); flagUsages != "" {
|
||||
fmt.Fprintf(w, "```\n%s````\n\n", dedent(flagUsages))
|
||||
}
|
||||
|
||||
// Subcommands
|
||||
for _, c := range cmd.Commands() {
|
||||
if c.Hidden {
|
||||
continue
|
||||
}
|
||||
cmdRef(w, c, depth+1)
|
||||
}
|
||||
}
|
||||
|
|
@ -47,6 +47,9 @@ var HelpTopics = map[string]map[string]string{
|
|||
error if a newer version was found.
|
||||
`),
|
||||
},
|
||||
"reference": {
|
||||
"short": "A comprehensive reference of all gh commands",
|
||||
},
|
||||
}
|
||||
|
||||
func NewHelpTopic(topic string) *cobra.Command {
|
||||
|
|
@ -55,8 +58,6 @@ func NewHelpTopic(topic string) *cobra.Command {
|
|||
Short: HelpTopics[topic]["short"],
|
||||
Long: HelpTopics[topic]["long"],
|
||||
Hidden: true,
|
||||
Args: cobra.NoArgs,
|
||||
Run: helpTopicHelpFunc,
|
||||
Annotations: map[string]string{
|
||||
"markdown:generate": "true",
|
||||
"markdown:basename": "gh_help_" + topic,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func TestNewHelpTopic(t *testing.T) {
|
|||
topic: "environment",
|
||||
args: []string{"invalid"},
|
||||
flags: []string{},
|
||||
wantsErr: true,
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "more than zero flags",
|
||||
|
|
@ -48,7 +48,7 @@ func TestNewHelpTopic(t *testing.T) {
|
|||
topic: "environment",
|
||||
args: []string{"help"},
|
||||
flags: []string{},
|
||||
wantsErr: true,
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "help flag",
|
||||
|
|
|
|||
|
|
@ -92,9 +92,14 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) *cobra.Command {
|
|||
|
||||
// Help topics
|
||||
cmd.AddCommand(NewHelpTopic("environment"))
|
||||
referenceCmd := NewHelpTopic("reference")
|
||||
referenceCmd.SetHelpFunc(referenceHelpFn(f.IOStreams))
|
||||
cmd.AddCommand(referenceCmd)
|
||||
|
||||
cmdutil.DisableAuthCheck(cmd)
|
||||
|
||||
// this needs to appear last:
|
||||
referenceCmd.Long = referenceLong(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,23 @@ func Render(text, style string, baseURL string) (string, error) {
|
|||
return tr.Render(text)
|
||||
}
|
||||
|
||||
func RenderWrap(text, style string, wrap int) (string, error) {
|
||||
// Glamour rendering preserves carriage return characters in code blocks, but
|
||||
// we need to ensure that no such characters are present in the output.
|
||||
text = strings.ReplaceAll(text, "\r\n", "\n")
|
||||
|
||||
tr, err := glamour.NewTermRenderer(
|
||||
glamour.WithStylePath(style),
|
||||
// glamour.WithBaseURL(""), // TODO: make configurable
|
||||
glamour.WithWordWrap(wrap),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tr.Render(text)
|
||||
}
|
||||
|
||||
func GetStyle(defaultStyle string) string {
|
||||
style := fromEnv()
|
||||
if style != "" && style != "auto" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue