dynamo-browse/internal/common/ui/commandctrl/commandctrl.go
Leon Mika 24304d21c3 issue-9: added the RC file
Added the RC file which can be used to load commands on startup.  Also added the "echo"
command which can be used for debugging.
2022-08-28 10:54:25 +10:00

116 lines
2.6 KiB
Go

package commandctrl
import (
"bufio"
"bytes"
tea "github.com/charmbracelet/bubbletea"
"github.com/pkg/errors"
"log"
"os"
"path/filepath"
"strings"
"github.com/lmika/audax/internal/common/ui/events"
"github.com/lmika/shellwords"
)
type CommandController struct {
commandList *CommandList
}
func NewCommandController() *CommandController {
return &CommandController{
commandList: nil,
}
}
func (c *CommandController) AddCommands(ctx *CommandList) {
ctx.parent = c.commandList
c.commandList = ctx
}
func (c *CommandController) Prompt() tea.Msg {
return events.PromptForInputMsg{
Prompt: ":",
OnDone: func(value string) tea.Msg {
return c.Execute(value)
},
}
}
func (c *CommandController) Execute(commandInput string) tea.Msg {
return c.execute(ExecContext{FromFile: false}, commandInput)
}
func (c *CommandController) execute(ctx ExecContext, commandInput string) tea.Msg {
input := strings.TrimSpace(commandInput)
if input == "" {
return nil
}
tokens := shellwords.Split(input)
command := c.lookupCommand(tokens[0])
if command == nil {
return events.Error(errors.New("no such command: " + tokens[0]))
}
return command(ctx, tokens[1:])
}
func (c *CommandController) Alias(commandName string) Command {
return func(ctx ExecContext, args []string) tea.Msg {
command := c.lookupCommand(commandName)
if command == nil {
return events.Error(errors.New("no such command: " + commandName))
}
return command(ctx, args)
}
}
func (c *CommandController) lookupCommand(name string) Command {
for ctx := c.commandList; ctx != nil; ctx = ctx.parent {
if cmd, ok := ctx.Commands[name]; ok {
return cmd
}
}
return nil
}
func (c *CommandController) ExecuteFile(filename string) error {
baseFilename := filepath.Base(filename)
if rcFile, err := os.ReadFile(filename); err == nil {
if err := c.executeFile(rcFile, baseFilename); err != nil {
return errors.Wrapf(err, "error executing %v", filename)
}
} else {
return errors.Wrapf(err, "error loading %v", filename)
}
return nil
}
func (c *CommandController) executeFile(file []byte, filename string) error {
scnr := bufio.NewScanner(bytes.NewReader(file))
lineNo := 0
for scnr.Scan() {
lineNo++
line := strings.TrimSpace(scnr.Text())
if line == "" {
continue
} else if line[0] == '#' {
continue
}
msg := c.execute(ExecContext{FromFile: true}, line)
switch m := msg.(type) {
case events.ErrorMsg:
log.Printf("%v:%v: error - %v", filename, lineNo, m.Error())
case events.StatusMsg:
log.Printf("%v:%v: %v", filename, lineNo, string(m))
}
}
return scnr.Err()
}