CLI: implement help

This commit is contained in:
kayos@tcp.direct 2022-09-26 10:10:17 -07:00
parent 40d8979ab9
commit 08b7a3f7ae
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
6 changed files with 136 additions and 68 deletions

@ -23,7 +23,7 @@ var (
extraDebug = false extraDebug = false
) )
// Interpret is where we will actuall define our CLICommands // Interpret is where we will actuall define our Commands
func executor(cmd string) { func executor(cmd string) {
cmd = strings.TrimSpace(cmd) cmd = strings.TrimSpace(cmd)
var args = strings.Fields(cmd) var args = strings.Fields(cmd)
@ -60,7 +60,7 @@ func executor(cmd string) {
} }
case "help": case "help":
if len(args) < 2 { if len(args) < 2 {
getHelp("meta") getHelp("")
return return
} }
getHelp(args[len(args)-1]) getHelp(args[len(args)-1])
@ -77,7 +77,7 @@ func executor(cmd string) {
if len(args) == 0 { if len(args) == 0 {
return return
} }
bcmd, ok := CLICommands[args[0]] bcmd, ok := Commands[args[0]]
if !ok { if !ok {
return return
} }
@ -109,18 +109,6 @@ func executor(cmd string) {
} }
} }
func getHelp(target string) {
/* if target == "" {
*/
for _, sug := range suggestions {
for _, su := range sug {
println(su.Text + "(" + strings.Join(su.inner.aliases, ", ") + ")\t" + su.Description)
}
}
return
// }
}
func cmdScan(br *ziggy.Bridge, args []string) error { func cmdScan(br *ziggy.Bridge, args []string) error {
r, err := br.FindLights() r, err := br.FindLights()
if err != nil { if err != nil {

@ -22,22 +22,23 @@ var (
) )
type ziggsCommand struct { type ziggsCommand struct {
reactor reactor reactor reactor
aliases []string description string
isAlias bool aliases []string
isAlias bool
} }
type reactor func(bridge *ziggy.Bridge, args []string) error type reactor func(bridge *ziggy.Bridge, args []string) error
func newZiggsCommand( func newZiggsCommand(react reactor, desc string, aliases ...string) *ziggsCommand {
react reactor,
aliases ...string) *ziggsCommand {
ret := &ziggsCommand{ ret := &ziggsCommand{
reactor: react, reactor: react,
isAlias: false, aliases: aliases,
isAlias: false,
description: desc,
} }
for _, alias := range aliases { for _, alias := range aliases {
CLICommands[alias] = &ziggsCommand{ Commands[alias] = &ziggsCommand{
reactor: react, reactor: react,
isAlias: true, isAlias: true,
} }
@ -45,21 +46,7 @@ func newZiggsCommand(
return ret return ret
} }
var CLICommands = make(map[string]*ziggsCommand) var Commands = make(map[string]*ziggsCommand)
func init() {
CLICommands["ls"] = newZiggsCommand(cmdList)
CLICommands["schedules"] = newZiggsCommand(cmdSchedules, "lssched", "crontab")
CLICommands["rules"] = newZiggsCommand(cmdRules, "lsrule")
CLICommands["sensors"] = newZiggsCommand(cmdSensors, "lssens")
CLICommands["scenes"] = newZiggsCommand(cmdScenes, "lsscene")
CLICommands["lights"] = newZiggsCommand(cmdLights, "lslight")
CLICommands["groups"] = newZiggsCommand(cmdGroups, "lsgrp")
CLICommands["delete"] = newZiggsCommand(cmdDelete, "del", "remove")
CLICommands["scan"] = newZiggsCommand(cmdScan, "search", "find")
CLICommands["rename"] = newZiggsCommand(cmdRename, "mv")
CLICommands["set"] = newZiggsCommand(cmdSet, "update")
}
func cmdList(br *ziggy.Bridge, args []string) error { func cmdList(br *ziggy.Bridge, args []string) error {
var runs = []reactor{cmdLights, cmdGroups, cmdScenes, cmdSensors} var runs = []reactor{cmdLights, cmdGroups, cmdScenes, cmdSensors}
@ -91,7 +78,9 @@ func cmdScenes(br *ziggy.Bridge, args []string) error {
return err return err
} }
for _, scene := range scenes { for _, scene := range scenes {
log.Info().Str("caller", scene.Name).Msgf("%v", spew.Sprint(scene)) log.Info().Str("caller", strings.Split(br.Host, "://")[1]).
Str("ID", scene.ID).Msgf("Scene: %s", scene.Name)
log.Trace().Msgf("%v", spew.Sprint(scene))
} }
return nil return nil
} }
@ -99,8 +88,9 @@ func cmdScenes(br *ziggy.Bridge, args []string) error {
func cmdLights(br *ziggy.Bridge, args []string) error { func cmdLights(br *ziggy.Bridge, args []string) error {
for name, l := range ziggy.GetLightMap() { for name, l := range ziggy.GetLightMap() {
log.Info(). log.Info().
Int("ID", l.ID).Str("type", l.ProductName). Str("caller", strings.Split(br.Host, "://")[1]).Int("ID", l.ID).Str("type", l.ProductName).
Str("model", l.ModelID).Bool("on", l.IsOn()).Msgf("[+] %s", name) Str("model", l.ModelID).Bool("on", l.IsOn()).Msgf("Light: %s", name)
log.Trace().Msgf("%v", spew.Sprint(l))
} }
return nil return nil
} }
@ -114,7 +104,9 @@ func cmdRules(br *ziggy.Bridge, args []string) error {
return errors.New("no rules found") return errors.New("no rules found")
} }
for _, r := range rules { for _, r := range rules {
log.Info().Str("caller", r.Name).Int("ID", r.ID).Msgf("%v", spew.Sprint(r)) log.Info().Str("caller", strings.Split(br.Host, "://")[1]).Int("ID", r.ID).
Str("status", r.Status).Msgf("Rule: %s", r.Name)
log.Trace().Msgf("%v", spew.Sprint(r))
} }
return nil return nil
} }
@ -128,7 +120,9 @@ func cmdSchedules(br *ziggy.Bridge, args []string) error {
return errors.New("no schedules found") return errors.New("no schedules found")
} }
for _, s := range schedules { for _, s := range schedules {
log.Info().Str("caller", s.Name).Int("ID", s.ID).Msgf("%v", spew.Sprint(s)) log.Info().Str("caller", strings.Split(br.Host, "://")[1]).Int("ID", s.ID).
Str("desc", s.Description).Msgf("Schedule: %s", s.Name)
log.Trace().Msgf("%v", spew.Sprint(s))
} }
return nil return nil
} }
@ -142,7 +136,9 @@ func cmdSensors(br *ziggy.Bridge, args []string) error {
return errors.New("no sensors found") return errors.New("no sensors found")
} }
for _, s := range sensors { for _, s := range sensors {
log.Info().Str("caller", s.Name).Int("ID", s.ID).Msgf("%v", spew.Sprint(s)) log.Info().Str("caller", strings.Split(br.Host, "://")[1]).Int("ID", s.ID).
Str("type", s.Type).Msgf("Sensor: %s", s.Name)
log.Trace().Msgf("%v", spew.Sprint(s))
} }
return nil return nil
} }
@ -156,8 +152,10 @@ func cmdGroups(br *ziggy.Bridge, args []string) error {
return errors.New("no groups found") return errors.New("no groups found")
} }
for n, g := range groupmap { for n, g := range groupmap {
log.Info().Str("caller", g.Name).Str("mapname", n).Str("type", g.Type).Int("ID", g.ID). log.Info().Str("caller", strings.Split(br.Host, "://")[1]).
Str("class", g.Class).Bool("on", g.IsOn()).Msgf("%v", g.GroupState) Str("mapname", n).Str("type", g.Type).Int("ID", g.ID).
Str("class", g.Class).Bool("on", g.IsOn()).Msgf("Group: %s", g.Name)
log.Trace().Msgf("%v", spew.Sprint(g))
} }
return nil return nil
} }

@ -9,7 +9,6 @@ import (
const ( const (
grn = "\033[32m" grn = "\033[32m"
red = "\033[31m" red = "\033[31m"
ylw = "\033[33m"
rst = "\033[0m" rst = "\033[0m"
) )
@ -17,6 +16,7 @@ type completion struct {
cli.Suggest cli.Suggest
inner *ziggsCommand inner *ziggsCommand
requires map[int][]string requires map[int][]string
isAlias bool
root bool root bool
} }
@ -65,30 +65,61 @@ func (c completion) qualifies(line string) bool {
return count >= len(c.requires) return count >= len(c.requires)
} }
var suggestions map[int][]completion var suggestions map[int][]*completion
func init() { func init() {
suggestions = make(map[int][]completion) Commands["ls"] = newZiggsCommand(cmdList, "list all lights, groups, scenes, rules, and schedules")
suggestions[0] = []completion{ Commands["schedules"] = newZiggsCommand(cmdSchedules, "list schedules", "lssched", "crontab")
{Suggest: cli.Suggest{Text: "lights", Description: "print all known lights"}, inner: CLICommands["lights"], root: true}, Commands["rules"] = newZiggsCommand(cmdRules, "list rules", "lsrule")
{Suggest: cli.Suggest{Text: "groups", Description: "print all known groups"}, inner: CLICommands["groups"], root: true}, Commands["sensors"] = newZiggsCommand(cmdSensors, "list sensors", "lssens")
{Suggest: cli.Suggest{Text: "rules", Description: "print all known rules"}, inner: CLICommands["rules"], root: true}, Commands["scenes"] = newZiggsCommand(cmdScenes, "list scenes", "lsscene")
{Suggest: cli.Suggest{Text: "scenes", Description: "print all known scenes"}, inner: CLICommands["scenes"], root: true}, Commands["lights"] = newZiggsCommand(cmdLights, "list lights", "lslight")
{Suggest: cli.Suggest{Text: "schedules", Description: "print all known schedules"}, inner: CLICommands["schedules"], root: true}, Commands["groups"] = newZiggsCommand(cmdGroups, "list groups", "lsgrp")
{Suggest: cli.Suggest{Text: "sensors", Description: "print all known sensors"}, inner: CLICommands["sensors"], root: true}, Commands["create"] = newZiggsCommand(cmdCreate, "create a new object in bridge", "new", "mk")
{Suggest: cli.Suggest{Text: "set", Description: "set state of target"}, inner: CLICommands["set"], root: true}, Commands["delete"] = newZiggsCommand(cmdDelete, "delete objects from bridges", "del", "remove")
{Suggest: cli.Suggest{Text: "create", Description: "create object"}, inner: CLICommands["create"], root: true}, Commands["scan"] = newZiggsCommand(cmdScan, "scan for bridges/lights/sensors", "search", "find")
{Suggest: cli.Suggest{Text: "delete", Description: "delete object"}, inner: CLICommands["delete"], root: true}, Commands["rename"] = newZiggsCommand(cmdRename, "rename object in bridge", "mv")
{Suggest: cli.Suggest{Text: "clear", Description: "clear screen"}}, Commands["set"] = newZiggsCommand(cmdSet, "update object properties in bridge", "update")
{Suggest: cli.Suggest{Text: "scan", Description: "scan for bridges"}}, initCompletion()
{Suggest: cli.Suggest{Text: "exit", Description: "exit ziggs"}}, }
func initCompletion() {
suggestions = make(map[int][]*completion)
suggestions[0] = []*completion{
{Suggest: cli.Suggest{Text: "lights"}, inner: Commands["lights"]},
{Suggest: cli.Suggest{Text: "groups"}, inner: Commands["groups"]},
{Suggest: cli.Suggest{Text: "rules"}, inner: Commands["rules"]},
{Suggest: cli.Suggest{Text: "scenes"}, inner: Commands["scenes"]},
{Suggest: cli.Suggest{Text: "schedules"}, inner: Commands["schedules"]},
{Suggest: cli.Suggest{Text: "sensors"}, inner: Commands["sensors"]},
{Suggest: cli.Suggest{Text: "set"}, inner: Commands["set"]},
{Suggest: cli.Suggest{Text: "create"}, inner: Commands["create"]},
{Suggest: cli.Suggest{Text: "delete"}, inner: Commands["delete"]},
{Suggest: cli.Suggest{Text: "scan"}, inner: Commands["scan"]},
{Suggest: cli.Suggest{Text: "use", Description: "select bridge to perform actions on"}}, {Suggest: cli.Suggest{Text: "use", Description: "select bridge to perform actions on"}},
{Suggest: cli.Suggest{Text: "clear", Description: "clear screen"}},
{Suggest: cli.Suggest{Text: "exit", Description: "exit ziggs"}},
} }
for _, sug := range suggestions[0] { for _, sug := range suggestions[0] {
sug.requires = map[int][]string{} sug.requires = map[int][]string{}
sug.root = true sug.root = true
if sug.inner != nil {
sug.Suggest.Description = sug.inner.description
}
if sug.inner != nil && len(sug.inner.aliases) > 0 {
for _, a := range sug.inner.aliases {
suggestions[0] = append(suggestions[0], &completion{
Suggest: cli.Suggest{Text: a, Description: sug.Description},
inner: sug.inner,
root: true,
isAlias: true,
})
}
}
} }
suggestions[1] = []completion{
suggestions[1] = []*completion{
{Suggest: cli.Suggest{Text: "group", Description: "target group"}}, {Suggest: cli.Suggest{Text: "group", Description: "target group"}},
{Suggest: cli.Suggest{Text: "light", Description: "target light"}}, {Suggest: cli.Suggest{Text: "light", Description: "target light"}},
} }
@ -96,7 +127,7 @@ func init() {
sug.requires = map[int][]string{0: {"delete", "del", "set", "s"}} sug.requires = map[int][]string{0: {"delete", "del", "set", "s"}}
sug.root = false sug.root = false
} }
delCompletion := []completion{ delCompletion := []*completion{
{Suggest: cli.Suggest{Text: "scene", Description: "target scene"}}, {Suggest: cli.Suggest{Text: "scene", Description: "target scene"}},
{Suggest: cli.Suggest{Text: "schedule", Description: "target schedule"}}, {Suggest: cli.Suggest{Text: "schedule", Description: "target schedule"}},
{Suggest: cli.Suggest{Text: "sensor", Description: "target sensor"}}, {Suggest: cli.Suggest{Text: "sensor", Description: "target sensor"}},

47
internal/cli/help.go Normal file

@ -0,0 +1,47 @@
package cli
import (
"fmt"
"os"
"strings"
"text/tabwriter"
)
var tabber = tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
func getHelp(target string) {
if target != "" && target != "meta" {
for _, su := range suggestions[0] {
if strings.Contains(strings.ToLower(su.Text), strings.ToLower(target)) {
println(su.Text + "\t" + su.Description)
}
}
return
}
for _, su := range suggestions[0] {
var desc string
if su.inner == nil {
desc = su.Description
} else {
desc = su.inner.description
if su.inner.isAlias || su.isAlias {
su.isAlias = true
if extraDebug {
log.Trace().Msgf("alias: %s", su.Text)
}
}
}
if su.isAlias {
continue
}
if extraDebug {
log.Trace().Interface("details", su).Send()
}
_, err := fmt.Fprintln(tabber, su.Text+"\t"+desc)
if err != nil {
panic(err.Error())
}
}
tabber.Flush()
}

@ -14,7 +14,7 @@ func processGroups(grps map[string]*huego.Group) {
suffix = " (" + g.Type + ")" suffix = " (" + g.Type + ")"
} }
suggestions[2] = append(suggestions[2], suggestions[2] = append(suggestions[2],
completion{ &completion{
Suggest: cli.Suggest{ Suggest: cli.Suggest{
Text: grp, Text: grp,
Description: "Group" + suffix, Description: "Group" + suffix,
@ -35,7 +35,7 @@ func processLights() {
suffix = " (" + l.Type + ")" suffix = " (" + l.Type + ")"
} }
suggestions[2] = append(suggestions[2], suggestions[2] = append(suggestions[2],
completion{ &completion{
Suggest: cli.Suggest{ Suggest: cli.Suggest{
Text: lt, Text: lt,
Description: "Light" + suffix, Description: "Light" + suffix,
@ -52,7 +52,7 @@ func processLights() {
func processBridges() { func processBridges() {
for brd, b := range ziggy.Lucifer.Bridges { for brd, b := range ziggy.Lucifer.Bridges {
suggestions[1] = append(suggestions[1], suggestions[1] = append(suggestions[1],
completion{ &completion{
Suggest: cli.Suggest{ Suggest: cli.Suggest{
Text: brd, Text: brd,
Description: "Bridge: " + b.Host, Description: "Bridge: " + b.Host,

@ -125,6 +125,10 @@ func main() {
data.Start() data.Start()
defer data.Close() defer data.Close()
if len(os.Args) < 2 {
cli.StartCLI()
}
for _, arg := range os.Args { for _, arg := range os.Args {
switch arg { switch arg {
case "discover": case "discover":