<commit_before>package cli

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	cmds "github.com/jbenet/go-ipfs/commands"
)

const (
	requiredArg = "<%v>"
	optionalArg = "[<%v>]"
	variadicArg = "%v..."
	optionFlag  = "-%v"
	optionType  = "(%v)"

	whitespace = "\r\n\t "

	indentStr = "    "
)

type helpFields struct {
	Indent      string
	Path        string
	ArgUsage    string
	Tagline     string
	Arguments   string
	Options     string
	Subcommands string
	Description string
}

const usageFormat = "{{.Path}}{{if .ArgUsage}} {{.ArgUsage}}{{end}} - {{.Tagline}}"

const longHelpFormat = `
{{.Indent}}{{template "usage" .}}

{{if .Arguments}}ARGUMENTS:

{{.Indent}}{{.Arguments}}

{{end}}{{if .Options}}OPTIONS:

{{.Indent}}{{.Options}}

{{end}}{{if .Subcommands}}SUBCOMMANDS:

{{.Indent}}{{.Subcommands}}

{{.Indent}}Use '{{.Path}} <subcmd> --help' for more information about each command.

{{end}}{{if .Description}}DESCRIPTION:

{{.Indent}}{{.Description}}

{{end}}
`
const shortHelpFormat = `USAGE:
{{.Indent}}{{template "usage" .}}
{{if .Description}}
{{.Indent}}{{.Description}}
{{end}}
Use '{{.Path}} --help' for more information about this command.
`

var usageTemplate *template.Template
var longHelpTemplate *template.Template
var shortHelpTemplate *template.Template

func init() {
	tmpl, err := template.New("usage").Parse(usageFormat)
	if err != nil {
		panic(err)
	}
	usageTemplate = tmpl

	tmpl, err = usageTemplate.New("longHelp").Parse(longHelpFormat)
	if err != nil {
		panic(err)
	}
	longHelpTemplate = tmpl

	tmpl, err = usageTemplate.New("shortHelp").Parse(shortHelpFormat)
	if err != nil {
		panic(err)
	}
	shortHelpTemplate = tmpl
}

// LongHelp returns a formatted CLI helptext string, generated for the given command
func LongHelp(rootName string, root *cmds.Command, path []string, out io.Writer) error {
	cmd, err := root.Get(path)
	if err != nil {
		return err
	}

	pathStr := rootName
	if len(path) > 0 {
		pathStr += " " + strings.Join(path, " ")
	}

	fields := helpFields{
		Indent:      indentStr,
		Path:        pathStr,
		ArgUsage:    usageText(cmd),
		Tagline:     cmd.Description,
		Arguments:   cmd.ArgumentHelp,
		Options:     cmd.OptionHelp,
		Subcommands: cmd.SubcommandHelp,
		Description: cmd.Help,
	}

	// autogen fields that are empty
	if len(cmd.ArgumentHelp) == 0 {
		fields.Arguments = strings.Join(argumentText(cmd), "\n")
	}
	if len(cmd.OptionHelp) == 0 {
		fields.Options = strings.Join(optionText(cmd), "\n")
	}
	if len(cmd.SubcommandHelp) == 0 {
		fields.Subcommands = strings.Join(subcommandText(cmd, rootName, path), "\n")
	}

	fields.Arguments = indentString(fields.Arguments, indentStr)
	fields.Options = indentString(fields.Options, indentStr)
	fields.Subcommands = indentString(fields.Subcommands, indentStr)
	fields.Description = indentString(fields.Description, indentStr)

	return longHelpTemplate.Execute(out, fields)
}

// ShortHelp returns a formatted CLI helptext string, generated for the given command
func ShortHelp(rootName string, root *cmds.Command, path []string, out io.Writer) error {
	cmd, err := root.Get(path)
	if err != nil {
		return err
	}

	pathStr := rootName
	if len(path) > 0 {
		pathStr += " " + strings.Join(path, " ")
	}

	fields := helpFields{
		Indent:      indentStr,
		Path:        pathStr,
		ArgUsage:    usageText(cmd),
		Tagline:     cmd.Description,
		Description: cmd.Help,
	}

	fields.Description = indentString(fields.Description, indentStr)

	return shortHelpTemplate.Execute(out, fields)
}

func argumentText(cmd *cmds.Command) []string {
	lines := make([]string, len(cmd.Arguments))

	for i, arg := range cmd.Arguments {
		lines[i] = argUsageText(arg)
		lines[i] += "\n" + arg.Description<commit_msg>commands/cli: Transitionary commit - Generate helptext from HelpText fields if they aren't empty<commit_after>package cli

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	cmds "github.com/jbenet/go-ipfs/commands"
)

const (
	requiredArg = "<%v>"
	optionalArg = "[<%v>]"
	variadicArg = "%v..."
	optionFlag  = "-%v"
	optionType  = "(%v)"

	whitespace = "\r\n\t "

	indentStr = "    "
)

type helpFields struct {
	Indent      string
	Usage       string
	Path        string
	ArgUsage    string
	Tagline     string
	Arguments   string
	Options     string
	Subcommands string
	Description string
}

const usageFormat = "{{if .Usage}}{{.Usage}}{{else}}{{.Path}}{{if .ArgUsage}} {{.ArgUsage}}{{end}} - {{.Tagline}}{{end}}"

const longHelpFormat = `
{{.Indent}}{{template "usage" .}}

{{if .Arguments}}ARGUMENTS:

{{.Indent}}{{.Arguments}}

{{end}}{{if .Options}}OPTIONS:

{{.Indent}}{{.Options}}

{{end}}{{if .Subcommands}}SUBCOMMANDS:

{{.Indent}}{{.Subcommands}}

{{.Indent}}Use '{{.Path}} <subcmd> --help' for more information about each command.

{{end}}{{if .Description}}DESCRIPTION:

{{.Indent}}{{.Description}}

{{end}}
`
const shortHelpFormat = `USAGE:
{{.Indent}}{{template "usage" .}}
{{if .Description}}
{{.Indent}}{{.Description}}
{{end}}
Use '{{.Path}} --help' for more information about this command.
`

var usageTemplate *template.Template
var longHelpTemplate *template.Template
var shortHelpTemplate *template.Template

func init() {
	tmpl, err := template.New("usage").Parse(usageFormat)
	if err != nil {
		panic(err)
	}
	usageTemplate = tmpl

	tmpl, err = usageTemplate.New("longHelp").Parse(longHelpFormat)
	if err != nil {
		panic(err)
	}
	longHelpTemplate = tmpl

	tmpl, err = usageTemplate.New("shortHelp").Parse(shortHelpFormat)
	if err != nil {
		panic(err)
	}
	shortHelpTemplate = tmpl
}

// LongHelp returns a formatted CLI helptext string, generated for the given command
func LongHelp(rootName string, root *cmds.Command, path []string, out io.Writer) error {
	cmd, err := root.Get(path)
	if err != nil {
		return err
	}

	pathStr := rootName
	if len(path) > 0 {
		pathStr += " " + strings.Join(path, " ")
	}

	// TODO: get the fields from the HelpText struct by default (when commands are ported to use it)
	fields := helpFields{
		Indent:      indentStr,
		Path:        pathStr,
		ArgUsage:    usageText(cmd),
		Tagline:     cmd.Description,
		Arguments:   cmd.ArgumentHelp,
		Options:     cmd.OptionHelp,
		Subcommands: cmd.SubcommandHelp,
		Description: cmd.Help,
	}

	// TODO: don't do these checks, just use these fields by default (when commands get ported to it)
	if len(cmd.Helptext.Tagline) > 0 {
		fields.Tagline = cmd.Helptext.Tagline
	}
	if len(cmd.Helptext.ShortDescription) > 0 {
		fields.Description = cmd.Helptext.ShortDescription
	}
	if len(cmd.Helptext.Usage) > 0 {
		fields.Usage = cmd.Helptext.Subcommands
	}

	// autogen fields that are empty
	if len(cmd.ArgumentHelp) == 0 {
		fields.Arguments = strings.Join(argumentText(cmd), "\n")
	}
	if len(cmd.OptionHelp) == 0 {
		fields.Options = strings.Join(optionText(cmd), "\n")
	}
	if len(cmd.SubcommandHelp) == 0 {
		fields.Subcommands = strings.Join(subcommandText(cmd, rootName, path), "\n")
	}

	fields.Arguments = indentString(fields.Arguments, indentStr)
	fields.Options = indentString(fields.Options, indentStr)
	fields.Subcommands = indentString(fields.Subcommands, indentStr)
	fields.Description = indentString(fields.Description, indentStr)

	return longHelpTemplate.Execute(out, fields)
}

// ShortHelp returns a formatted CLI helptext string, generated for the given command
func ShortHelp(rootName string, root *cmds.Command, path []string, out io.Writer) error {
	cmd, err := root.Get(path)
	if err != nil {
		return err
	}

	pathStr := rootName
	if len(path) > 0 {
		pathStr += " " + strings.Join(path, " ")
	}

	fields := helpFields{
		Indent:      indentStr,
		Path:        pathStr,
		ArgUsage:    usageText(cmd),
		Tagline:     cmd.Description,
		Description: cmd.Help,
	}

	// TODO: don't do these checks, just use these fields by default (when commands get ported to it)
	if len(cmd.Helptext.Tagline) > 0 {
		fields.Tagline = cmd.Helptext.Tagline
	}
	if len(cmd.Helptext.Arguments) > 0 {
		fields.Arguments = cmd.Helptext.Arguments
	}
	if len(cmd.Helptext.Options) > 0 {
		fields.Options = cmd.Helptext.Options
	}
	if len(cmd.Helptext.Subcommands) > 0 {
		fields.Subcommands = cmd.Helptext.Subcommands
	}
	if len(cmd.Helptext.LongDescription) > 0 {
		fields.Description = cmd.Helptext.LongDescription
	} else if len(cmd.Helptext.ShortDescription) > 0 {
		fields.Description = cmd.Helptext.ShortDescription
	}
	if len(cmd.Helptext.Usage) > 0 {
		fields.Usage = cmd.Helptext.Subcommands
	}

	fields.Description = indentString(fields.Description, indentStr)

	return shortHelpTemplate.Execute(out, fields)
}

func argumentText(cmd *cmds.Command) []string {
	lines := make([]string, len(cmd.Arguments))

	for i, arg := range cmd.Arguments {
		lines[i] = argUsageText(arg)
		lines[i] += "\n" + arg.Description
{'fraction_non_alphanumeric': 0.14940947139089553, 'fraction_numerical': 0.002293314986813439, 'mean_word_length': 4.035796766743649, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4976830', 'n_tokens_mistral': 3071, 'n_tokens_neox': 2959, 'n_words': 711}