diff --git a/app.go b/app.go
index 0a1a3f5..99904b2 100644
--- a/app.go
+++ b/app.go
@@ -28,7 +28,7 @@ func WithInput(in config.BindProvider) func(*App) {
// WithSkipArgs sets how many arguments are passed. For example, you don't need to pass the name of a single command.
func WithSkipArgs(l int) func(*App) {
- return WithInput(chain.New(arg.New(arg.WithSkip(l)), &memory.Default{}))
+ return WithInput(chain.New(arg.New(arg.WithArgs(os.Args[resolveSkip(l):])), &memory.Default{}))
}
// WithExit sets exit callback by default os.Exit.
@@ -43,7 +43,7 @@ func New(opts ...func(*App)) *App {
app := &App{
out: output.Stdout(),
exit: os.Exit,
- in: chain.New(arg.New(arg.WithSkip(0)), &memory.Default{}),
+ in: chain.New(arg.New(arg.WithArgs(os.Args[resolveSkip(0):])), &memory.Default{}),
}
for _, opt := range opts {
@@ -125,3 +125,20 @@ func (a *App) list(ctx context.Context) error {
func (a *App) printError(ctx context.Context, err error) {
ansi(ctx, a.in, a.out).Println(ctx, "\n\n ", err, "\n")
}
+
+func resolveSkip(in int) int {
+ res := 2
+
+ switch {
+ case in > 0 && len(os.Args) > in:
+ res = in
+ case in > 0:
+ res = len(os.Args)
+ case len(os.Args) == 1:
+ res = 1
+ case len(os.Args) > 1 && os.Args[1][0] == '-':
+ res = 1
+ }
+
+ return res
+}
diff --git a/app_test.go b/app_test.go
index 4b8e2d5..04f841b 100644
--- a/app_test.go
+++ b/app_test.go
@@ -30,21 +30,21 @@ func ExampleNew_help() {
// test:command [options] [--] []
//
// Arguments:
- // test_argument test argument
+ // test_argument test argument
//
// Options:
- // --string[=STRING] array string (multiple values allowed)
- // --group-bool bool
- // --group-test-string[=GROUP-TEST-STRING] test group string [default: group string default value]
- // --log-{service}-level[=LOG-{SERVICE}-LEVEL] service level [default: debug]
- // --bool test bool option
- // --duration[=DURATION] test duration with default [default: 1s]
- // --ansi Do not ask any interactive question
- // -V, --version Display this application version
- // -h, --help Display this help message
- // -v, --verbose Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace (multiple values allowed)
- // -q, --quiet Do not output any message
- // --no-ansi Disable ANSI output
+ // --string[=STRING] array string (multiple values allowed)
+ // --group-bool bool
+ // --group-test-string[=GROUP-TEST-STRING] test group string [default:group string default value]
+ // --log-{service}-level[=LOG-{SERVICE}-LEVEL] service level [default:debug]
+ // --bool test bool option
+ // --duration[=DURATION] test duration with default
+ // --ansi Do not ask any interactive question
+ // -V, --version Display this application version
+ // -h, --help Display this help message
+ // -v, --verbose Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace (multiple values allowed)
+ // -q, --quiet Do not output any message
+ // --no-ansi Disable ANSI output
}
func ExampleNew_list() {
@@ -81,7 +81,7 @@ func ExampleNew_list() {
// --ansi Do not ask any interactive question
// -V, --version Display this application version
// -h, --help Display this help message
- // -v, --verbose Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace (multiple values allowed)
+ // -v, --verbose Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace (multiple values allowed)
// -q, --quiet Do not output any message
//
// Available commands:
diff --git a/go.mod b/go.mod
index d4dee3a..4108a0b 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module gitoa.ru/go-4devs/console
go 1.24.0
-require gitoa.ru/go-4devs/config v0.0.7
+require gitoa.ru/go-4devs/config v0.0.8
require (
golang.org/x/mod v0.31.0 // indirect
diff --git a/go.sum b/go.sum
index 8514eac..28f9a61 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,10 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-gitoa.ru/go-4devs/config v0.0.7 h1:8q6axRNLgXE5dYQd8Jbh9j+STqevbibVyvwrtsuHpZk=
-gitoa.ru/go-4devs/config v0.0.7/go.mod h1:UINWnObZA0nLiJro+TtavUBBvN0cSt17aRHOk20pP74=
+gitoa.ru/go-4devs/config v0.0.8 h1:o4p8I9jWJMfiFVVKr50IqCGj1fF+8kmSPDkH0deRvn4=
+gitoa.ru/go-4devs/config v0.0.8/go.mod h1:jHKqVafFVW400LC0M4i1ifPapiI9sqpX/QTh+VMadKw=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
-golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
diff --git a/help.go b/help.go
index 4eaea7f..172874a 100644
--- a/help.go
+++ b/help.go
@@ -9,6 +9,7 @@ import (
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition"
"gitoa.ru/go-4devs/config/definition/option"
+ "gitoa.ru/go-4devs/config/param"
"gitoa.ru/go-4devs/config/provider/arg"
"gitoa.ru/go-4devs/config/validator"
"gitoa.ru/go-4devs/config/value"
@@ -70,7 +71,7 @@ To display the list of available commands, please use the list comm
Name: cmd.Name,
Description: cmd.Description,
Help: cmd.Help,
- Definition: descriptor.NewDefinition(config.NewVars(def.Options()...).Variables()),
+ Options: def.With(param.New(descriptor.TxtStyle())),
})
if derr != nil {
return fmt.Errorf("descriptor help:%w", derr)
diff --git a/list.go b/list.go
index 56b14c7..8a6b6ac 100644
--- a/list.go
+++ b/list.go
@@ -8,6 +8,7 @@ import (
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition"
"gitoa.ru/go-4devs/config/definition/option"
+ "gitoa.ru/go-4devs/config/param"
"gitoa.ru/go-4devs/config/provider/arg"
"gitoa.ru/go-4devs/config/validator"
"gitoa.ru/go-4devs/config/value"
@@ -71,8 +72,8 @@ func executeList(ctx context.Context, in config.Provider, out output.Output) err
cmds := Commands()
commands := descriptor.Commands{
- Namespace: ns,
- Definition: descriptor.NewDefinition(config.NewVars(definition.New(Default()...).Options()...).Variables()),
+ Namespace: ns,
+ Options: definition.New(Default()...).With(param.New(descriptor.TxtStyle())),
}
groups := make(map[string]*descriptor.NSCommand)
namespaces := make([]string, 0, len(cmds))
diff --git a/output/descriptor/descriptor.go b/output/descriptor/descriptor.go
index 174623e..405afb1 100644
--- a/output/descriptor/descriptor.go
+++ b/output/descriptor/descriptor.go
@@ -3,13 +3,9 @@ package descriptor
import (
"context"
"errors"
- "sort"
- "strings"
"sync"
"gitoa.ru/go-4devs/config"
- "gitoa.ru/go-4devs/config/definition/option"
- "gitoa.ru/go-4devs/config/provider/arg"
"gitoa.ru/go-4devs/console/output"
)
@@ -24,17 +20,19 @@ var (
)
type Command struct {
+ config.Options
+
Bin string
Name string
Description string
Help string
- Definition Definition
}
type Commands struct {
- Namespace string
- Definition Definition
- Commands []NSCommand
+ config.Options
+
+ Namespace string
+ Commands []NSCommand
}
type NSCommand struct {
@@ -46,65 +44,6 @@ func (n *NSCommand) Append(name, desc string) {
n.Commands = append(n.Commands, ShortCommand{Name: name, Description: desc})
}
-func NewDefinition(opts []config.Variable) Definition {
- type data struct {
- name string
- pos uint64
- opt config.Variable
- }
-
- posArgs := make([]data, 0, len(opts))
-
- posOpt := make([]data, 0, len(opts))
- for _, opt := range opts {
- pos, ok := arg.ParamArgument(opt)
- if !ok {
- pos, _ = option.DataPosition(opt)
- posOpt = append(posOpt, data{pos: pos, opt: opt})
-
- continue
- }
-
- posArgs = append(posArgs, data{name: strings.Join(opt.Key(), "."), pos: pos, opt: opt})
- }
-
- sort.Slice(posArgs, func(i, j int) bool {
- return posArgs[i].pos > posArgs[j].pos && posArgs[i].name > posArgs[j].name
- })
-
- sort.Slice(posOpt, func(i, j int) bool {
- return posOpt[i].pos < posOpt[j].pos
- })
-
- args := make([]config.Variable, len(posArgs))
- for idx := range posArgs {
- args[idx] = posArgs[idx].opt
- }
-
- options := make([]config.Variable, len(posOpt))
- for idx := range posOpt {
- options[idx] = posOpt[idx].opt
- }
-
- return Definition{
- options: options,
- args: args,
- }
-}
-
-type Definition struct {
- args []config.Variable
- options []config.Variable
-}
-
-func (d Definition) Arguments() []config.Variable {
- return d.args
-}
-
-func (d Definition) Options() []config.Variable {
- return d.options
-}
-
type ShortCommand struct {
Name string
Description string
diff --git a/output/descriptor/txt.go b/output/descriptor/txt.go
index d09396b..c6b4dc4 100644
--- a/output/descriptor/txt.go
+++ b/output/descriptor/txt.go
@@ -4,21 +4,18 @@ import (
"bytes"
"context"
"fmt"
- "strconv"
"strings"
"text/template"
- "time"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition/option"
"gitoa.ru/go-4devs/config/param"
- "gitoa.ru/go-4devs/config/value"
+ "gitoa.ru/go-4devs/config/provider/arg"
"gitoa.ru/go-4devs/console/output"
)
const (
defaultSpace = 2
- infoLen = 13
dashDelimiter = "-"
)
@@ -40,8 +37,8 @@ var (
{{ end -}}
Usage:
- {{ .Name }} {{ synopsis .Definition }}
-{{- definition .Definition }}
+ {{ .Name }} {{ synopsis .Options }}
+{{ definition .Options }}
{{- help . }}
`))
@@ -49,11 +46,24 @@ var (
Funcs(txtFunc).
Parse(`Usage:
command [options] [arguments]
-{{- definition .Definition }}
+{{ 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 {
@@ -82,54 +92,6 @@ func (t *txt) Commands(ctx context.Context, out output.Output, cmds Commands) er
return nil
}
-func txtDefaultArray(val config.Value) string {
- var st any
-
- err := val.Unmarshal(&st)
- if err != nil {
- return ""
- }
-
- return fmt.Sprintf("%v", st)
-}
-
-//nolint:cyclop
-func txtDefault(val config.Value, vr config.Variable) []byte {
- var buf bytes.Buffer
-
- buf.WriteString(" [default: ")
-
- dataType := param.Type(vr)
- if option.IsSlice(vr) {
- buf.WriteString(txtDefaultArray(val))
- } else {
- switch dataType.(type) {
- case int:
- buf.WriteString(strconv.Itoa(val.Int()))
- case int64:
- buf.WriteString(strconv.FormatInt(val.Int64(), 10))
- case uint:
- buf.WriteString(strconv.FormatUint(uint64(val.Uint()), 10))
- case uint64:
- buf.WriteString(strconv.FormatUint(val.Uint64(), 10))
- case float64:
- buf.WriteString(strconv.FormatFloat(val.Float64(), 'g', -1, 64))
- case time.Duration:
- buf.WriteString(val.Duration().String())
- case time.Time:
- buf.WriteString(val.Time().Format(time.RFC3339))
- case string:
- buf.WriteString(val.String())
- default:
- buf.WriteString(fmt.Sprint(val.Any()))
- }
- }
-
- buf.WriteString("]")
-
- return buf.Bytes()
-}
-
func txtCommands(cmds []NSCommand) string {
width := commandsTotalWidth(cmds)
showNS := len(cmds) > 1
@@ -181,95 +143,20 @@ func txtHelp(cmd Command) string {
return buf.String()
}
-func txtDefinitionOption(maxLen int, opts ...config.Variable) string {
- buf := bytes.Buffer{}
- buf.WriteString("\n\nOptions:\n")
-
- for _, opt := range opts {
- if option.IsHidden(opt) {
- continue
- }
-
- var op bytes.Buffer
-
- op.WriteString(" ")
-
- if short, ok := option.ParamShort(opt); ok {
- op.WriteString("-")
- op.WriteString(short)
- op.WriteString(", ")
- } else {
- op.WriteString(" ")
- }
-
- op.WriteString("--")
- op.WriteString(strings.Join(opt.Key(), dashDelimiter))
-
- if !option.IsBool(opt) {
- if !option.IsRequired(opt) {
- op.WriteString("[")
- }
-
- op.WriteString("=")
- op.WriteString(strings.ToUpper(strings.Join(opt.Key(), dashDelimiter)))
-
- if !option.IsRequired(opt) {
- op.WriteString("]")
- }
- }
-
- op.WriteString("")
- buf.Write(op.Bytes())
- buf.WriteString(strings.Repeat(" ", maxLen+17-op.Len()))
- buf.WriteString(option.DataDescription(opt))
-
- if data, ok := option.DataDefaut(opt); ok {
- buf.Write(txtDefault(value.New(data), opt))
- }
-
- if option.IsSlice(opt) {
- buf.WriteString(" (multiple values allowed)")
- }
-
- buf.WriteString("\n")
- }
-
- return buf.String()
-}
-
-func txtDefinition(def Definition) string {
- width := totalWidth(def)
-
+func txtDefinition(options config.Options) string {
var buf bytes.Buffer
- if args := def.Arguments(); len(args) > 0 {
- buf.WriteString("\n\nArguments:\n")
-
- for _, arg := range args {
- var ab bytes.Buffer
-
- ab.WriteString(" ")
- ab.WriteString(strings.Join(arg.Key(), dashDelimiter))
- ab.WriteString("")
- ab.WriteString(strings.Repeat(" ", width+infoLen+defaultSpace-ab.Len()))
-
- buf.Write(ab.Bytes())
- buf.WriteString(option.DataDescription(arg))
-
- if data, ok := option.DataDefaut(arg); ok {
- buf.Write(txtDefault(value.New(data), arg))
- }
- }
- }
-
- if opts := def.Options(); len(opts) > 0 {
- buf.WriteString(txtDefinitionOption(width, opts...))
+ err := arg.NewDump().Reference(&buf, options)
+ if err != nil {
+ return err.Error()
}
return buf.String()
}
-func txtSynopsis(def Definition) string {
+func txtSynopsis(options config.Options) string {
+ def := arg.NewViews(options, nil)
+
var buf bytes.Buffer
if len(def.Options()) > 0 {
@@ -294,7 +181,7 @@ func txtSynopsis(def Definition) string {
}
buf.WriteString("<")
- buf.WriteString(strings.Join(arg.Key(), dashDelimiter))
+ buf.WriteString(arg.Name(dashDelimiter))
buf.WriteString(">")
if option.IsSlice(arg) {
@@ -320,32 +207,3 @@ func commandsTotalWidth(cmds []NSCommand) int {
return width
}
-
-//nolint:mnd
-func totalWidth(def Definition) int {
- var width int
-
- for _, arg := range def.Arguments() {
- if l := len(strings.Join(arg.Key(), dashDelimiter)); l > width {
- width = l
- }
- }
-
- for _, opt := range def.Options() {
- current := len(strings.Join(opt.Key(), dashDelimiter)) + 6
-
- if !option.IsBool(opt) {
- current = current*2 + 1
- }
-
- if _, ok := option.DataDefaut(opt); ok {
- current += 2
- }
-
- if current > width {
- width = current
- }
- }
-
- return width
-}