From 223b699dec73fb79e88998bc4616dd1c7760df65 Mon Sep 17 00:00:00 2001 From: qowevisa Date: Wed, 16 Oct 2024 23:07:31 +0300 Subject: [PATCH] Add some state of library --- simple/erros.go | 9 +++ simple/menu.go | 201 ++++++++++++++++++++++++++++++++++++++++++++++ simple/options.go | 15 ++++ 3 files changed, 225 insertions(+) create mode 100644 simple/erros.go create mode 100644 simple/menu.go create mode 100644 simple/options.go diff --git a/simple/erros.go b/simple/erros.go new file mode 100644 index 0000000..8413e34 --- /dev/null +++ b/simple/erros.go @@ -0,0 +1,9 @@ +package simple + +import "errors" + +var ( + // {{{ IS NOT INIT + CommandTree_notInit = errors.New("Command tree is not initialized") + // }}} +) diff --git a/simple/menu.go b/simple/menu.go new file mode 100644 index 0000000..57a32b4 --- /dev/null +++ b/simple/menu.go @@ -0,0 +1,201 @@ +package simple + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +type Command struct { + id uint + Key string + Name string + Descr string + Action CommandAction + MoveTo bool +} + +type CommandAction func(m *Menu) error + +func EmptyAction(m *Menu) error { + return nil +} + +func (c *Command) Print() { + if c.Descr != "" { + fmt.Printf("%s: %s (%s)\n", c.Key, c.Name, c.Descr) + } else { + fmt.Printf("%s: %s\n", c.Key, c.Name) + } +} + +type MenuConfig struct { + Title string + BackKey string +} + +func getDefConfig() *MenuConfig { + return &MenuConfig{ + Title: "Default Menu Title", + BackKey: "<", + } +} + +type commandNode struct { + Val *Command + Children []*commandNode + Parent *commandNode +} + +func createCommandNodeWoParent(cmd *Command) *commandNode { + return &commandNode{ + Val: cmd, + Children: []*commandNode{}, + } +} +func createCommandNode(cmd *Command, parent *commandNode) *commandNode { + return &commandNode{ + Val: cmd, + Children: []*commandNode{}, + Parent: parent, + } +} + +func (cn *commandNode) AddChild(child *commandNode) { + cn.Children = append(cn.Children, child) +} + +type commandTree struct { + Root *commandNode + Pointer *commandNode +} + +func createCommandTree() *commandTree { + root := createCommandNode(&Command{ + Name: "Root", + }, nil) + return &commandTree{ + Root: root, + Pointer: root, + } +} + +type Menu struct { + Title string + BackKey string + // + counterForIDs uint + cmdTree *commandTree +} + +func CreateMenu(options ...SimpleMenuOption) *Menu { + conf := getDefConfig() + + for _, opt := range options { + opt(conf) + } + + return &Menu{ + Title: conf.Title, + BackKey: conf.BackKey, + counterForIDs: 1, + cmdTree: createCommandTree(), + } +} + +func (node *commandNode) AddCommand(key, name string, action CommandAction) *commandNode { + cmd := &Command{ + Key: key, + Name: name, + Action: action, + MoveTo: true, + } + newNode := createCommandNode(cmd, node) + node.AddChild(newNode) + + return newNode +} + +func (node *commandNode) AddExecCommand(key, name string, action CommandAction) *commandNode { + cmd := &Command{ + Key: key, + Name: name, + Action: action, + MoveTo: false, + } + newNode := createCommandNode(cmd, node) + node.AddChild(newNode) + + return newNode +} + +func (node *commandNode) AddGroupingCommand(key, name string) *commandNode { + cmd := &Command{ + Key: key, + Name: name, + Action: EmptyAction, + MoveTo: true, + } + newNode := createCommandNode(cmd, node) + node.AddChild(newNode) + + return newNode +} + +func (m *Menu) AddCommand(key, name string, action CommandAction) (*commandNode, error) { + if m.cmdTree == nil { + return nil, CommandTree_notInit + } + return m.cmdTree.Root.AddCommand(key, name, action), nil +} + +func (m *Menu) iteration() { + fmt.Printf("%s\n", m.Title) + path := "" + for node := m.cmdTree.Pointer; node != nil; node = node.Parent { + if node.Parent == nil { + path += node.Val.Name + } else { + path += fmt.Sprintf("%s -> ", node.Val.Name) + } + } + fmt.Printf("At %s\n", path) + for _, node := range m.cmdTree.Pointer.Children { + cmd := node.Val + if cmd == nil { + // TODO: Check it + continue + } + cmd.Print() + } + if m.cmdTree.Pointer != m.cmdTree.Root { + fmt.Printf("%s: Go back one layer\n", m.BackKey) + } + stdinReader := bufio.NewReader(os.Stdin) + msg, err := stdinReader.ReadString('\n') + if err != nil { + fmt.Printf("Error: ReadString: %v\n", err) + return + } + msg = strings.TrimRight(msg, "\n") + for _, node := range m.cmdTree.Pointer.Children { + cmd := node.Val + if cmd == nil { + continue + } + if cmd.Key == msg { + cmd.Action(m) + m.cmdTree.Pointer = node + } + } + if m.BackKey == msg { + m.cmdTree.Pointer = m.cmdTree.Pointer.Parent + } +} + +func (m *Menu) Start() { + for { + m.iteration() + } +} diff --git a/simple/options.go b/simple/options.go new file mode 100644 index 0000000..ac030d8 --- /dev/null +++ b/simple/options.go @@ -0,0 +1,15 @@ +package simple + +type SimpleMenuOption func(conf *MenuConfig) + +func WithCustomTitle(title string) SimpleMenuOption { + return func(conf *MenuConfig) { + conf.Title = title + } +} + +func WithCustomBackKey(back string) SimpleMenuOption { + return func(conf *MenuConfig) { + conf.BackKey = back + } +}