-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ feat(interact): add new interactive component input-collector
- Loading branch information
Showing
9 changed files
with
352 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,115 @@ | ||
package interact | ||
|
||
import "github.com/gookit/goutil/maputil" | ||
import ( | ||
"github.com/gookit/goutil/arrutil" | ||
"github.com/gookit/goutil/errorx" | ||
"github.com/gookit/goutil/maputil" | ||
"github.com/gookit/goutil/structs" | ||
"github.com/gookit/goutil/strutil" | ||
) | ||
|
||
// InputParameter interface | ||
type InputParameter interface { | ||
Type() string | ||
Name() string | ||
Desc() string | ||
Value() structs.Value | ||
Set(v string) error | ||
Run() error | ||
} | ||
|
||
// Collector information collector 信息收集者 | ||
// cli input values collector | ||
type Collector struct { | ||
qs []*Question | ||
ans maputil.Data | ||
// input parameters | ||
ps map[string]InputParameter | ||
ret maputil.Data | ||
err error | ||
|
||
ns []string | ||
} | ||
|
||
// NewCollector instance | ||
func NewCollector() *Collector { | ||
return &Collector{} | ||
return &Collector{ | ||
ps: make(map[string]InputParameter), | ||
ret: make(maputil.Data), | ||
} | ||
} | ||
|
||
// AddParams definitions at once. | ||
func (c *Collector) AddParams(ps ...InputParameter) error { | ||
for _, p := range ps { | ||
if err := c.AddParam(p); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Param get from collector | ||
func (c *Collector) Param(name string) (InputParameter, bool) { | ||
p, ok := c.ps[name] | ||
return p, ok | ||
} | ||
|
||
// MustParam get from collector | ||
func (c *Collector) MustParam(name string) InputParameter { | ||
p, ok := c.ps[name] | ||
if !ok { | ||
panic("not found the param: " + name) | ||
} | ||
|
||
return p | ||
} | ||
|
||
// AddParam to collector | ||
func (c *Collector) AddParam(p InputParameter) error { | ||
if strutil.IsBlank(p.Name()) { | ||
return errorx.Raw("input parameter name cannot be empty") | ||
} | ||
|
||
name := p.Name() | ||
if arrutil.Contains(c.ns, name) { | ||
return errorx.Rawf("input parameter name %s has been exists", name) | ||
} | ||
|
||
c.ns = append(c.ns, name) | ||
c.ps[name] = p | ||
|
||
return nil | ||
} | ||
|
||
// Results for collector | ||
func (c *Collector) Results() maputil.Data { | ||
return c.ret | ||
} | ||
|
||
// Run collector | ||
func (c *Collector) Run() error { | ||
if len(c.ns) == 0 { | ||
return errorx.Raw("empty params definitions") | ||
} | ||
|
||
for _, name := range c.ns { | ||
p := c.ps[name] | ||
|
||
// has input value | ||
if c.ret.Has(name) { | ||
err := p.Set(c.ret.Str(name)) | ||
if err != nil { | ||
return err | ||
} | ||
continue | ||
} | ||
|
||
// require input value | ||
if err := p.Run(); err != nil { | ||
return err | ||
} | ||
|
||
c.ret.Set(name, p.Value().V) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package interact_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/gookit/gcli/v3/interact" | ||
"github.com/gookit/gcli/v3/interact/cparam" | ||
"github.com/gookit/goutil/testutil/assert" | ||
) | ||
|
||
func TestCollector_Run(t *testing.T) { | ||
c := interact.NewCollector() | ||
err := c.AddParams( | ||
cparam.NewStringParam("title", "title name"), | ||
cparam.NewChoiceParam("projects", "select projects"), | ||
) | ||
|
||
assert.NoErr(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package control |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package cparam | ||
|
||
import ( | ||
"github.com/gookit/gcli/v3/interact" | ||
"github.com/gookit/goutil/errorx" | ||
) | ||
|
||
// ChoiceParam definition | ||
type ChoiceParam struct { | ||
InputParam | ||
// Choices for select | ||
Choices []string | ||
selected []string | ||
} | ||
|
||
// NewChoiceParam instance | ||
func NewChoiceParam(name, desc string) *ChoiceParam { | ||
return &ChoiceParam{ | ||
InputParam: InputParam{ | ||
typ: TypeChoicesParam, | ||
name: name, | ||
desc: desc, | ||
}, | ||
} | ||
} | ||
|
||
// WithChoices to param definition | ||
func (p *ChoiceParam) WithChoices(Choices []string) *ChoiceParam { | ||
p.Choices = Choices | ||
return p | ||
} | ||
|
||
// Selected values get | ||
func (p *ChoiceParam) Selected() []string { | ||
return p.val.Strings() | ||
} | ||
|
||
// Set value | ||
func (p *ChoiceParam) Set(v string) error { | ||
if err := p.Valid(v); err != nil { | ||
return err | ||
} | ||
|
||
p.selected = append(p.selected, v) | ||
p.val.Set(p.selected) | ||
return nil | ||
} | ||
|
||
// Run param and get user input | ||
func (p *ChoiceParam) Run() (err error) { | ||
if len(p.Choices) == 0 { | ||
return errorx.Raw("must provide items for choices") | ||
} | ||
|
||
s := interact.NewSelect(p.Desc(), p.Choices) | ||
s.EnableMulti() | ||
|
||
sr := s.Run() | ||
p.val.Set(sr.Val()) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package cparam | ||
|
||
import ( | ||
"github.com/gookit/goutil/errorx" | ||
"github.com/gookit/goutil/structs" | ||
) | ||
|
||
// params types | ||
const ( | ||
TypeStringParam = "string" | ||
TypeChoicesParam = "choices" | ||
) | ||
|
||
// RunFn func type | ||
type RunFn func() (val string, err error) | ||
|
||
// InputParam struct | ||
type InputParam struct { | ||
typ string | ||
name string | ||
desc string | ||
// Default value | ||
Default any | ||
ValidFn func(val string) error | ||
runFn func() (val string, err error) | ||
// Value for input | ||
val structs.Value | ||
err error | ||
} | ||
|
||
// NewInputParam instance | ||
func NewInputParam(typ, name, desc string) *InputParam { | ||
return &InputParam{ | ||
typ: typ, | ||
name: name, | ||
desc: desc, | ||
} | ||
} | ||
|
||
// Type name get | ||
func (p *InputParam) Type() string { | ||
return p.typ | ||
} | ||
|
||
// Name get | ||
func (p *InputParam) Name() string { | ||
return p.name | ||
} | ||
|
||
// Desc message | ||
func (p *InputParam) Desc() string { | ||
return p.desc | ||
} | ||
|
||
// Valid value validate | ||
func (p *InputParam) Valid(v string) error { | ||
if p.ValidFn != nil { | ||
return p.ValidFn(v) | ||
} | ||
return nil | ||
} | ||
|
||
// Set value and with validate | ||
func (p *InputParam) Set(v string) error { | ||
if err := p.Valid(v); err != nil { | ||
return err | ||
} | ||
|
||
p.val.Set(v) | ||
return nil | ||
} | ||
|
||
// Value data get | ||
func (p *InputParam) Value() structs.Value { | ||
return p.val | ||
} | ||
|
||
// Value get | ||
func (p *InputParam) String() string { | ||
return p.val.String() | ||
} | ||
|
||
// SetFunc for run | ||
func (p *InputParam) SetFunc(fn RunFn) { | ||
p.runFn = fn | ||
} | ||
|
||
// SetValidFn for run | ||
func (p *InputParam) SetValidFn(fn func(val string) error) { | ||
p.ValidFn = fn | ||
} | ||
|
||
// Run param and get user input | ||
func (p *InputParam) Run() (err error) { | ||
if p.runFn != nil { | ||
val, err := p.runFn() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = p.Set(val) | ||
} else { | ||
err = errorx.Raw("please implement me") | ||
} | ||
|
||
return err | ||
} |
Oops, something went wrong.