package descriptor
import (
"bytes"
"context"
"fmt"
"strings"
"text/template"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition/option"
"gitoa.ru/go-4devs/config/param"
"gitoa.ru/go-4devs/config/provider/arg"
"gitoa.ru/go-4devs/console/output"
"gitoa.ru/go-4devs/console/setting"
)
const (
defaultSpace = 2
dashDelimiter = "-"
)
//nolint:gochecknoglobals
var (
txtFunc = template.FuncMap{
"definition": txtDefinition,
"help": txtHelp,
"usage": txtUsage,
"commands": txtCommands,
}
txtHelpTemplate = template.Must(
template.New("txt_template").
Funcs(txtFunc).
Parse(`
{{- if .Description -}}
Description:
{{ .Description }}
{{ end -}}
{{- usage . }}
{{- definition .Options }}
{{- help . }}`),
)
txtListTemplate = template.Must(template.New("txt_list").
Funcs(txtFunc).
Parse(`Usage:
command [options] [arguments]
{{ definition .Options }}
{{- commands .Commands -}}
`))
)
func TxtStyle() param.Option {
return arg.WithStyle(
arg.Style{
Start: "",
End: "",
},
arg.Style{
Start: "",
End: "",
},
)
}
type txt struct{}
func (t *txt) Command(ctx context.Context, out output.Output, cmd Command) error {
var tpl bytes.Buffer
err := txtHelpTemplate.Execute(&tpl, cmd)
if err != nil {
return fmt.Errorf("execute txt help tpl:%w", err)
}
out.Println(ctx, tpl.String())
return nil
}
func (t *txt) Commands(ctx context.Context, out output.Output, cmds Commands) error {
var buf bytes.Buffer
err := txtListTemplate.Execute(&buf, cmds)
if err != nil {
return fmt.Errorf("execute txt list tpl:%w", err)
}
out.Println(ctx, buf.String())
return nil
}
func txtCommands(cmds []NSCommand) string {
width := commandsTotalWidth(cmds)
showNS := len(cmds) > 1
var buf bytes.Buffer
buf.WriteString("\nAvailable commands")
if len(cmds) == 1 && cmds[0].Name != "" {
buf.WriteString("for the \"")
buf.WriteString(cmds[0].Name)
buf.WriteString(`" namespace`)
}
buf.WriteString(":\n")
for _, ns := range cmds {
if ns.Name != "" && showNS {
buf.WriteString("")
buf.WriteString(ns.Name)
buf.WriteString("\n")
}
for _, cmd := range ns.Commands {
buf.WriteString(" ")
buf.WriteString(cmd.Name)
buf.WriteString("")
buf.WriteString(strings.Repeat(" ", width-len(cmd.Name)+defaultSpace))
buf.WriteString(cmd.Description)
buf.WriteString("\n")
}
}
return buf.String()
}
func txtUsage(cmd Command) string {
if cmd.Usage == nil {
return ""
}
data, has := cmd.Usage()
if has && data == "" {
return ""
}
if data == "" {
data = defaultUsage(setting.UsageData(cmd.Name, cmd.Options))
}
return "\nUsage:\n " + data + "\n"
}
func txtHelp(cmd Command) string {
if cmd.Help == "" {
return ""
}
return "\nHelp:\n" + cmd.Help + "\n"
}
func txtDefinition(options config.Options) string {
var buf bytes.Buffer
err := arg.NewDump().Reference(&buf, options)
if err != nil {
return err.Error()
}
return buf.String()
}
func defaultUsage(data setting.UData) string {
def := arg.NewViews(data.Options, nil)
var buf bytes.Buffer
buf.WriteString(data.Name)
buf.WriteString(" ")
if len(def.Options()) > 0 {
buf.WriteString("[options] ")
}
args := def.Arguments()
if buf.Len() > 0 && len(args) > 0 {
buf.WriteString("[--]")
}
var opt int
for _, arg := range args {
buf.WriteString(" ")
if !option.IsRequired(arg) {
buf.WriteString("[")
opt++
}
buf.WriteString("<")
buf.WriteString(arg.Name(dashDelimiter))
buf.WriteString(">")
if option.IsSlice(arg) {
buf.WriteString("...")
}
}
buf.WriteString(strings.Repeat("]", opt))
return buf.String()
}
func commandsTotalWidth(cmds []NSCommand) int {
var width int
for _, ns := range cmds {
for _, cmd := range ns.Commands {
if len(cmd.Name) > width {
width = len(cmd.Name)
}
}
}
return width
}