ucl: integrated ucl with the command evaluator

This commit is contained in:
Leon Mika 2024-05-01 21:30:47 +10:00
parent e37b8099a3
commit b2ddc62555
7 changed files with 170 additions and 98 deletions

View file

@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"strings"
"ucl.lmika.dev/ucl"
"github.com/lmika/dynamo-browse/internal/common/ui/events"
"github.com/lmika/shellwords"
@ -18,18 +19,25 @@ import (
const commandsCategory = "commands"
type CommandController struct {
uclInst *ucl.Inst
historyProvider IterProvider
commandList *CommandList
msgSender func(tea.Msg)
lookupExtensions []CommandLookupExtension
completionProvider CommandCompletionProvider
}
func NewCommandController(historyProvider IterProvider) *CommandController {
return &CommandController{
cc := &CommandController{
historyProvider: historyProvider,
commandList: nil,
lookupExtensions: nil,
}
cc.uclInst = ucl.New(
ucl.WithOut(ucl.LineHandler(cc.printLine)),
ucl.WithMissingBuiltinHandler(cc.cmdInvoker),
)
return cc
}
func (c *CommandController) AddCommands(ctx *CommandList) {
@ -37,6 +45,10 @@ func (c *CommandController) AddCommands(ctx *CommandList) {
c.commandList = ctx
}
func (c *CommandController) SetMessageSender(msg func(tea.Msg)) {
c.msgSender = msg
}
func (c *CommandController) AddCommandLookupExtension(ext CommandLookupExtension) {
c.lookupExtensions = append(c.lookupExtensions, ext)
}
@ -83,29 +95,25 @@ func (c *CommandController) execute(ctx ExecContext, commandInput string) tea.Ms
return nil
}
tokens := shellwords.Split(input)
command := c.lookupCommand(tokens[0])
if command == nil {
return events.Error(errors.New("no such command: " + tokens[0]))
res, err := c.uclInst.Eval(context.Background(), commandInput)
if err != nil {
return events.Error(err)
}
return command(ctx, tokens[1:])
if teaMsg, ok := res.(teaMsgWrapper); ok {
return teaMsg.msg
}
return nil
}
func (c *CommandController) Alias(commandName string, aliasArgs []string) Command {
return func(ctx ExecContext, args []string) tea.Msg {
func (c *CommandController) Alias(commandName string) Command {
return func(ctx ExecContext, args ucl.CallArgs) tea.Msg {
command := c.lookupCommand(commandName)
if command == nil {
return events.Error(errors.New("no such command: " + commandName))
}
var allArgs []string
if len(aliasArgs) > 0 {
allArgs = append(append([]string{}, aliasArgs...), args...)
} else {
allArgs = args
}
return command(ctx, allArgs)
return command(ctx, args)
}
}
@ -160,3 +168,26 @@ func (c *CommandController) executeFile(file []byte, filename string) error {
}
return scnr.Err()
}
func (c *CommandController) cmdInvoker(ctx context.Context, name string, args ucl.CallArgs) (any, error) {
command := c.lookupCommand(name)
if command == nil {
return nil, errors.New("no such command: " + name)
}
res := command(ExecContext{}, args)
if errMsg, isErrMsg := res.(events.ErrorMsg); isErrMsg {
return nil, errMsg
}
return teaMsgWrapper{res}, nil
}
func (c *CommandController) printLine(s string) {
if c.msgSender != nil {
c.msgSender(events.StatusMsg(s))
}
}
type teaMsgWrapper struct {
msg tea.Msg
}

View file

@ -1,11 +1,14 @@
package commandctrl
import tea "github.com/charmbracelet/bubbletea"
import (
tea "github.com/charmbracelet/bubbletea"
"ucl.lmika.dev/ucl"
)
type Command func(ctx ExecContext, args []string) tea.Msg
type Command func(ctx ExecContext, args ucl.CallArgs) tea.Msg
func NoArgCommand(cmd tea.Cmd) Command {
return func(ctx ExecContext, args []string) tea.Msg {
return func(ctx ExecContext, args ucl.CallArgs) tea.Msg {
return cmd()
}
}