Overhaul and fix CLI completion
This commit is contained in:
parent
d16319f2a9
commit
74d9ac7346
@ -31,9 +31,10 @@ type ziggsCommand struct {
|
|||||||
description string
|
description string
|
||||||
aliases []string
|
aliases []string
|
||||||
isAlias bool
|
isAlias bool
|
||||||
|
requires int // number of arguments required
|
||||||
}
|
}
|
||||||
|
|
||||||
func newZiggsCommand(react reactor, desc string, aliases ...string) *ziggsCommand {
|
func newZiggsCommand(react reactor, desc string, requires int, aliases ...string) *ziggsCommand {
|
||||||
ret := &ziggsCommand{
|
ret := &ziggsCommand{
|
||||||
reactor: react,
|
reactor: react,
|
||||||
aliases: aliases,
|
aliases: aliases,
|
||||||
|
@ -15,22 +15,18 @@ const (
|
|||||||
type completion struct {
|
type completion struct {
|
||||||
cli.Suggest
|
cli.Suggest
|
||||||
inner *ziggsCommand
|
inner *ziggsCommand
|
||||||
requires map[int][]string
|
requires map[int]map[string]bool
|
||||||
isAlias bool
|
isAlias bool
|
||||||
root bool
|
root bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c completion) qualifies(line string) bool {
|
func (c completion) qualifies(line string) bool {
|
||||||
args := strings.Fields(line)
|
args := strings.Fields(line)
|
||||||
if len(line) == 0 {
|
|
||||||
return false
|
if len(args) <= 1 && c.root {
|
||||||
}
|
|
||||||
if c.root && len(args) < 1 {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
/*if c.root && len(args) > 0 {
|
|
||||||
return false
|
|
||||||
}*/
|
|
||||||
if len(args) < len(c.requires) {
|
if len(args) < len(c.requires) {
|
||||||
if extraDebug {
|
if extraDebug {
|
||||||
log.Trace().Int("len(args)", len(args)).Int("len(c.requires)", len(c.requires)).
|
log.Trace().Int("len(args)", len(args)).Int("len(c.requires)", len(c.requires)).
|
||||||
@ -45,54 +41,60 @@ func (c completion) qualifies(line string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
has := func(b []string, a string) bool {
|
|
||||||
for _, r := range b {
|
|
||||||
if a == r {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
var count = 0
|
var count = 0
|
||||||
for i, a := range args {
|
for i, a := range args {
|
||||||
if has(c.requires[i], a) {
|
i++
|
||||||
|
if _, ok := c.requires[i][a]; ok {
|
||||||
if extraDebug {
|
if extraDebug {
|
||||||
log.Trace().Msgf("%v%s: found %s%v", grn, c.Text, a, rst)
|
log.Trace().Msgf("%v%s: found %s%v", grn, c.Text, a, rst)
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if extraDebug && !(count >= len(c.requires)) {
|
||||||
|
log.Trace().Msgf("%v%s: count(%d) < len(c.requires)(%d)", red, c.Text, count, len(c.requires))
|
||||||
|
}
|
||||||
|
|
||||||
return count >= len(c.requires)
|
return count >= len(c.requires)
|
||||||
}
|
}
|
||||||
|
|
||||||
var suggestions map[int][]*completion
|
var suggestions map[int]map[string]*completion
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Commands["ls"] = newZiggsCommand(cmdList, "list all lights, groups, scenes, rules, and schedules")
|
Commands["ls"] = newZiggsCommand(cmdList, "list all lights, groups, scenes, rules, and schedules", 0)
|
||||||
Commands["schedules"] = newZiggsCommand(cmdSchedules, "list schedules", "lssched", "crontab")
|
Commands["schedules"] = newZiggsCommand(cmdSchedules, "list schedules", 0,
|
||||||
Commands["rules"] = newZiggsCommand(cmdRules, "list rules", "lsrule")
|
"lssched", "crontab")
|
||||||
Commands["sensors"] = newZiggsCommand(cmdSensors, "list sensors", "lssens")
|
Commands["rules"] = newZiggsCommand(cmdRules, "list rules", 0, "lsrule")
|
||||||
Commands["scenes"] = newZiggsCommand(cmdScenes, "list scenes", "lsscene")
|
Commands["sensors"] = newZiggsCommand(cmdSensors, "list sensors", 0, "lssens")
|
||||||
Commands["lights"] = newZiggsCommand(cmdLights, "list lights", "lslight")
|
Commands["scenes"] = newZiggsCommand(cmdScenes, "list scenes", 0, "lsscene")
|
||||||
Commands["groups"] = newZiggsCommand(cmdGroups, "list groups", "lsgrp")
|
Commands["lights"] = newZiggsCommand(cmdLights, "list lights", 0, "lslight")
|
||||||
Commands["create"] = newZiggsCommand(cmdCreate, "create a new object in bridge", "new", "mk")
|
Commands["groups"] = newZiggsCommand(cmdGroups, "list groups", 0, "lsgrp")
|
||||||
Commands["delete"] = newZiggsCommand(cmdDelete, "delete objects from bridges", "del", "remove")
|
Commands["create"] = newZiggsCommand(cmdCreate, "create a new object in bridge", 3,
|
||||||
Commands["scan"] = newZiggsCommand(cmdScan, "scan for bridges/lights/sensors", "search", "find")
|
"new", "mk")
|
||||||
Commands["rename"] = newZiggsCommand(cmdRename, "rename object in bridge", "mv")
|
Commands["delete"] = newZiggsCommand(cmdDelete, "delete objects from bridges", 2,
|
||||||
Commands["adopt"] = newZiggsCommand(cmdAdopt, "adopt new lights to the bridge")
|
"del", "remove", "rm")
|
||||||
Commands["dump"] = newZiggsCommand(cmdDump, "dump target object JSON to a file")
|
Commands["scan"] = newZiggsCommand(cmdScan, "scan for bridges/lights/sensors", 0,
|
||||||
Commands["load"] = newZiggsCommand(cmdLoad, "load JSON from a file into the bridge")
|
"search", "find")
|
||||||
Commands["set"] = newZiggsCommand(cmdSet, "update object properties in bridge")
|
Commands["rename"] = newZiggsCommand(cmdRename, "rename object in bridge", 3, "mv")
|
||||||
Commands["fwupdate"] = newZiggsCommand(cmdFirmwareUpdate, "inform bridge to check for updates",
|
Commands["adopt"] = newZiggsCommand(cmdAdopt, "adopt new lights to the bridge", 0)
|
||||||
"fwup", "upgrade")
|
Commands["dump"] = newZiggsCommand(cmdDump, "dump target object JSON to a file", 1)
|
||||||
Commands["info"] = newZiggsCommand(cmdInfo, "show information about a bridge", "uname")
|
Commands["load"] = newZiggsCommand(cmdLoad, "load JSON from a file into the bridge", 1)
|
||||||
|
Commands["set"] = newZiggsCommand(cmdSet, "update object properties in bridge", 3)
|
||||||
|
Commands["upgrade"] = newZiggsCommand(cmdFirmwareUpdate, "inform bridge to check for updates", 0,
|
||||||
|
"fwup", "upgrade", "fwupdate")
|
||||||
|
Commands["info"] = newZiggsCommand(cmdInfo, "show information about a bridge", 0, "uname")
|
||||||
initCompletion()
|
initCompletion()
|
||||||
}
|
}
|
||||||
|
|
||||||
func initCompletion() {
|
func initCompletion() {
|
||||||
suggestions = make(map[int][]*completion)
|
suggestions = make(map[int]map[string]*completion)
|
||||||
suggestions[0] = []*completion{
|
suggestions[0] = make(map[string]*completion)
|
||||||
{Suggest: cli.Suggest{Text: "lights"}, inner: Commands["lights"]},
|
suggestions[1] = make(map[string]*completion)
|
||||||
|
suggestions[2] = make(map[string]*completion)
|
||||||
|
|
||||||
|
/* {Suggest: cli.Suggest{Text: "lights"}, inner: Commands["lights"]},
|
||||||
{Suggest: cli.Suggest{Text: "groups"}, inner: Commands["groups"]},
|
{Suggest: cli.Suggest{Text: "groups"}, inner: Commands["groups"]},
|
||||||
{Suggest: cli.Suggest{Text: "rules"}, inner: Commands["rules"]},
|
{Suggest: cli.Suggest{Text: "rules"}, inner: Commands["rules"]},
|
||||||
{Suggest: cli.Suggest{Text: "scenes"}, inner: Commands["scenes"]},
|
{Suggest: cli.Suggest{Text: "scenes"}, inner: Commands["scenes"]},
|
||||||
@ -107,63 +109,72 @@ func initCompletion() {
|
|||||||
{Suggest: cli.Suggest{Text: "dump"}, inner: Commands["dump"]},
|
{Suggest: cli.Suggest{Text: "dump"}, inner: Commands["dump"]},
|
||||||
{Suggest: cli.Suggest{Text: "load"}, inner: Commands["load"]},
|
{Suggest: cli.Suggest{Text: "load"}, inner: Commands["load"]},
|
||||||
{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"}},
|
{Suggest: cli.Suggest{Text: "exit", Description: "exit ziggs"}},
|
||||||
|
*/
|
||||||
|
|
||||||
|
suggestions[0]["clear"] = &completion{Suggest: cli.Suggest{Text: "clear", Description: "clear screen"}}
|
||||||
|
suggestions[0]["exit"] = &completion{Suggest: cli.Suggest{Text: "exit", Description: "exit ziggs"}}
|
||||||
|
suggestions[0]["help"] = &completion{Suggest: cli.Suggest{Text: "help", Description: "show help"}}
|
||||||
|
|
||||||
|
for name, cmd := range Commands {
|
||||||
|
suggestions[0][name] = &completion{Suggest: cli.Suggest{Text: name}, inner: cmd, root: cmd.requires == 0}
|
||||||
|
if cmd.description != "" {
|
||||||
|
suggestions[0][name].Description = cmd.description
|
||||||
|
}
|
||||||
|
suggestions[0][name].requires = map[int]map[string]bool{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sug := range suggestions[0] {
|
suggestions[1] = map[string]*completion{
|
||||||
sug.requires = map[int][]string{}
|
"group": {Suggest: cli.Suggest{Text: "group", Description: "target group"}},
|
||||||
sug.root = true
|
"light": {Suggest: cli.Suggest{Text: "light", Description: "target light"}},
|
||||||
if sug.inner != nil {
|
"scene": {Suggest: cli.Suggest{Text: "scene", Description: "target scene"}},
|
||||||
sug.Suggest.Description = sug.inner.description
|
"schedule": {Suggest: cli.Suggest{Text: "schedule", Description: "target schedule"}},
|
||||||
}
|
"sensor": {Suggest: cli.Suggest{Text: "sensor", Description: "target sensor"}},
|
||||||
if sug.inner != nil && len(sug.inner.aliases) > 0 {
|
"config": {Suggest: cli.Suggest{Text: "config", Description: "target bridge config"}},
|
||||||
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{
|
|
||||||
{Suggest: cli.Suggest{Text: "group", Description: "target group"}},
|
|
||||||
{Suggest: cli.Suggest{Text: "light", Description: "target light"}},
|
|
||||||
{Suggest: cli.Suggest{Text: "scene", Description: "target scene"}},
|
|
||||||
{Suggest: cli.Suggest{Text: "schedule", Description: "target schedule"}},
|
|
||||||
{Suggest: cli.Suggest{Text: "sensor", Description: "target sensor"}},
|
|
||||||
{Suggest: cli.Suggest{Text: "config", Description: "target bridge config"}},
|
|
||||||
}
|
}
|
||||||
for _, sug := range suggestions[1] {
|
for _, sug := range suggestions[1] {
|
||||||
sug.requires = map[int][]string{0: {"delete", "del", "set", "s", "rename", "mv", "dump", "load"}}
|
sug.requires = map[int]map[string]bool{1: {
|
||||||
|
"delete": true, "del": true, "set": true, "s": true, "rename": true, "mv": true, "dump": true, "load": true},
|
||||||
|
}
|
||||||
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"}},
|
||||||
|
{Suggest: cli.Suggest{Text: "group", Description: "target group"}},
|
||||||
}
|
}
|
||||||
for _, sug := range delCompletion {
|
for _, sug := range delCompletion {
|
||||||
sug.requires = map[int][]string{0: {"delete", "del"}}
|
sug.requires = map[int]map[string]bool{1: {"delete": true, "del": true}}
|
||||||
sug.root = false
|
sug.root = false
|
||||||
}
|
}
|
||||||
suggestions[1] = append(suggestions[1], delCompletion...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func completer(in cli.Document) []cli.Suggest {
|
func completer(in cli.Document) []cli.Suggest {
|
||||||
c := in.CurrentLine()
|
c := in.CurrentLine()
|
||||||
|
|
||||||
infields := strings.Fields(c)
|
infields := strings.Fields(c)
|
||||||
var head = len(infields) - 1
|
var head = len(infields) - 1
|
||||||
if len(infields) == 0 {
|
if head < 0 {
|
||||||
head = 0
|
head = 0
|
||||||
}
|
}
|
||||||
|
if head == 1 {
|
||||||
|
head = 1
|
||||||
|
}
|
||||||
|
if head > 0 && in.LastKeyStroke() == ' ' {
|
||||||
|
head++
|
||||||
|
}
|
||||||
|
|
||||||
|
if extraDebug {
|
||||||
|
log.Trace().Int("head", head).Msgf("completing %v", infields)
|
||||||
|
}
|
||||||
var sugs []cli.Suggest
|
var sugs []cli.Suggest
|
||||||
for _, sug := range suggestions[head] {
|
for _, sug := range suggestions[head] {
|
||||||
if sug.qualifies(c) && strings.HasPrefix(sug.Text, in.GetWordBeforeCursor()) {
|
if sug.qualifies(c) {
|
||||||
sugs = append(sugs, sug.Suggest)
|
if in.GetWordBeforeCursor() != "" && strings.HasPrefix(sug.Text, in.GetWordBeforeCursor()) {
|
||||||
|
sugs = append(sugs, sug.Suggest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sugs
|
return sugs
|
||||||
|
@ -13,18 +13,18 @@ func processGroups(grps map[string]*huego.Group) {
|
|||||||
if g.Type != "" {
|
if g.Type != "" {
|
||||||
suffix = " (" + g.Type + ")"
|
suffix = " (" + g.Type + ")"
|
||||||
}
|
}
|
||||||
suggestions[2] = append(suggestions[2],
|
|
||||||
&completion{
|
suggestions[2][grp] = &completion{
|
||||||
Suggest: cli.Suggest{
|
Suggest: cli.Suggest{
|
||||||
Text: grp,
|
Text: grp,
|
||||||
Description: "Group" + suffix,
|
Description: "Group" + suffix,
|
||||||
},
|
},
|
||||||
requires: map[int][]string{
|
requires: map[int]map[string]bool{
|
||||||
0: {"set", "s", "delete", "d"},
|
1: {"set": true, "s": true, "delete": true, "d": true},
|
||||||
1: {"group", "g"},
|
2: {"group": true, "g": true},
|
||||||
},
|
},
|
||||||
root: false,
|
root: false,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,31 +34,29 @@ func processLights() {
|
|||||||
if l.Type != "" {
|
if l.Type != "" {
|
||||||
suffix = " (" + l.Type + ")"
|
suffix = " (" + l.Type + ")"
|
||||||
}
|
}
|
||||||
suggestions[2] = append(suggestions[2],
|
suggestions[2][lt] = &completion{
|
||||||
&completion{
|
Suggest: cli.Suggest{
|
||||||
Suggest: cli.Suggest{
|
Text: lt,
|
||||||
Text: lt,
|
Description: "Light" + suffix,
|
||||||
Description: "Light" + suffix,
|
},
|
||||||
},
|
requires: map[int]map[string]bool{
|
||||||
requires: map[int][]string{
|
1: {"set": true, "s": true, "delete": true, "d": true},
|
||||||
0: {"set", "s", "delete", "d", "rename", "r"},
|
2: {"light": true, "l": true},
|
||||||
1: {"light", "l"},
|
},
|
||||||
},
|
root: false,
|
||||||
root: false,
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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]["bridge"] = &completion{
|
||||||
&completion{
|
Suggest: cli.Suggest{
|
||||||
Suggest: cli.Suggest{
|
Text: brd,
|
||||||
Text: brd,
|
Description: "Bridge: " + b.Host,
|
||||||
Description: "Bridge: " + b.Host,
|
},
|
||||||
},
|
requires: map[int]map[string]bool{0: {"use": true, "u": true}},
|
||||||
requires: map[int][]string{0: {"use", "u"}},
|
root: false,
|
||||||
root: false,
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user