205 lines
5.7 KiB
Go
205 lines
5.7 KiB
Go
package menus
|
|
|
|
/* ---------------------------------------------------------------- *
|
|
* IMPORTS
|
|
* ---------------------------------------------------------------- */
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"ads/internal/core/logging"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
/* ---------------------------------------------------------------- *
|
|
* METHOD menu class methods
|
|
* ---------------------------------------------------------------- */
|
|
|
|
func (menu *Menu) SetDefault(index int) {
|
|
menu.Default = index
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- *
|
|
* METHOD show menu
|
|
* ---------------------------------------------------------------- */
|
|
|
|
func (menu Menu) ShowMenu() (bool, error) {
|
|
var (
|
|
choice string
|
|
index int
|
|
meta bool
|
|
quit bool
|
|
cancel bool
|
|
err error
|
|
)
|
|
var promptMessages []string
|
|
var optionsFlattened []MenuOption
|
|
var optionsKeyValue [][2]string
|
|
var defaultOption string
|
|
var breaks []int
|
|
|
|
// Headline einfügen
|
|
promptMessages = make([]string, len(menu.PromptMessages))
|
|
copy(promptMessages, menu.PromptMessages)
|
|
head := fmt.Sprintf("\033[2m%s\033[0m", strings.Join(menu.Path, " > "))
|
|
promptMessages = append([]string{head}, promptMessages...)
|
|
|
|
// Zurück-Option einfügen
|
|
defaultOption = ""
|
|
if menu.Default >= 0 {
|
|
defaultOption = fmt.Sprintf("%v", menu.Default+1)
|
|
}
|
|
breaks = []int{}
|
|
optionsFlattened = []MenuOption{}
|
|
optionsKeyValue = []([2]string){}
|
|
index = 0
|
|
for _, suboptions := range menu.Options {
|
|
for _, opt := range suboptions {
|
|
optionsFlattened = append(optionsFlattened, opt)
|
|
key := fmt.Sprintf("%v", index+1)
|
|
subLabel := opt.SubLabel
|
|
label := opt.Label
|
|
if !(subLabel == "") {
|
|
label = fmt.Sprintf("%v (\033[2m%v\033[0m)", opt.Label, subLabel)
|
|
}
|
|
optionsKeyValue = append(optionsKeyValue, [2]string{key, label})
|
|
index++
|
|
}
|
|
breaks = append(breaks, index-1)
|
|
}
|
|
if !menu.IsRoot {
|
|
optionsKeyValue = append(optionsKeyValue, [2]string{"z", "Zurück zum vorherigen Menü"})
|
|
}
|
|
optionsKeyValue = append(optionsKeyValue, [2]string{"q", "Programm schließen"})
|
|
|
|
// User Response immer abfragen und abarbeiten, bis quit/return.
|
|
performClearScreen := !menu.IsRoot
|
|
for {
|
|
if performClearScreen {
|
|
logging.ClearScreen()
|
|
}
|
|
performClearScreen = true
|
|
|
|
choice, meta = promptListOfOptions(promptMessages, optionsKeyValue, breaks, defaultOption)
|
|
|
|
// Falls quit wählt, -> quit:
|
|
if (menu.IsRoot && meta) || choice == "q" {
|
|
return true, nil
|
|
}
|
|
|
|
// Falls User back wählt, -> return:
|
|
if (!menu.IsRoot && meta) || choice == "z" {
|
|
return false, nil
|
|
}
|
|
|
|
// sonst führe die assoziierte Methode aus
|
|
index64, _ := strconv.ParseInt(choice, 10, 64)
|
|
index = int(index64) - 1
|
|
if 0 <= index && index < len(optionsFlattened) {
|
|
opt := optionsFlattened[index]
|
|
// Entweder Untermenü öffnen oder Action ausführen
|
|
if opt.Submenu != nil {
|
|
quit, err = opt.Submenu.ShowMenu()
|
|
if quit {
|
|
return true, err
|
|
}
|
|
} else if opt.Action != nil {
|
|
cancel, err = opt.Action()
|
|
if err != nil {
|
|
logging.LogError(err)
|
|
}
|
|
// Falls ForceReturn, dann nach Ausführung der Action, -> return
|
|
if menu.ForceReturn {
|
|
return false, nil
|
|
} else {
|
|
// Falls während der Action der User Meta+D klickt, -> return:
|
|
if cancel {
|
|
continue
|
|
}
|
|
quit := logging.PromptAnyKeyToContinue()
|
|
// Falls nach der Action der User Meta+D klickt, -> quit:
|
|
if quit {
|
|
return true, nil
|
|
}
|
|
}
|
|
} else {
|
|
logging.LogWarn("Option noch nicht implementiert.")
|
|
quit := logging.PromptAnyKeyToContinue()
|
|
if quit {
|
|
return true, nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- *
|
|
* METHOD prompt values
|
|
* ---------------------------------------------------------------- */
|
|
|
|
func (query *PromptValueQuery) Prompt() (bool, error) {
|
|
var lines = []interface{}{}
|
|
var responsePtr = query.Response
|
|
var (
|
|
line string
|
|
cancel bool
|
|
err error
|
|
)
|
|
|
|
// prüfen, dass response ein Ptr auf eine Struct ist:
|
|
if !(reflect.ValueOf(responsePtr).Kind() == reflect.Ptr) || !(reflect.ValueOf(responsePtr).Elem().Kind() == reflect.Struct) {
|
|
panic("Input muss ein Pointer auf einen struct sein")
|
|
}
|
|
|
|
// prompt message vorbereiten:
|
|
lines = append(lines, fmt.Sprintf("%s, \033[1;3m%s\033[0m, als \033[1m%s\033[0m bitte eingeben.", query.Description, query.Name, query.Type))
|
|
if query.ValidExamples != nil && len(*query.ValidExamples) > 0 {
|
|
if len(*query.ValidExamples) == 1 {
|
|
example := (*query.ValidExamples)[0]
|
|
lines = append(lines, fmt.Sprintf(" \033[3;4mBeispiel von Input im gültigen Format:\033[0m \033[2m%s\033[0m", example))
|
|
} else {
|
|
lines = append(lines, fmt.Sprintf(" \033[3;4mBeispiele von Inputs im gültigen Format:\033[0m"))
|
|
for _, example := range *query.ValidExamples {
|
|
lines = append(lines, fmt.Sprintf(" - \033[2m%s\033[0m", example))
|
|
}
|
|
lines = append(lines, fmt.Sprintf(" - \033[2;3metc.\033[0m"))
|
|
}
|
|
}
|
|
if query.Requirements != nil && len(*query.Requirements) > 0 {
|
|
if len(*query.Requirements) == 1 {
|
|
requirement := (*query.Requirements)[0]
|
|
lines = append(lines, fmt.Sprintf(" \033[3;4mInput muss erfüllen:\033[0m \033[2m%s\033[0m", requirement))
|
|
} else {
|
|
lines = append(lines, fmt.Sprintf(" \033[3;4mInput muss erfüllen:\033[0m"))
|
|
for _, requirement := range *query.Requirements {
|
|
lines = append(lines, fmt.Sprintf(" - \033[2m%s\033[0m", requirement))
|
|
}
|
|
}
|
|
}
|
|
|
|
// prompt Eingabe eines Werts:
|
|
for {
|
|
line, cancel, err = logging.Prompt(lines...)
|
|
if cancel {
|
|
return true, nil
|
|
}
|
|
if err != nil {
|
|
logging.LogError(err, "")
|
|
continue
|
|
}
|
|
line = fmt.Sprintf("\"response\": %s", line)
|
|
err = yaml.Unmarshal([]byte(line), query.Response)
|
|
if err != nil {
|
|
logging.LogError(err, "")
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
|
|
return cancel, err
|
|
}
|