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.
This commit is contained in:
parent
d9c9e5d845
commit
24304d21c3
|
@ -33,7 +33,7 @@ func main() {
|
||||||
ctrl := controllers.NewLogFileController(service, flag.Arg(0))
|
ctrl := controllers.NewLogFileController(service, flag.Arg(0))
|
||||||
|
|
||||||
cmdController := commandctrl.NewCommandController()
|
cmdController := commandctrl.NewCommandController()
|
||||||
//cmdController.AddCommands(&commandctrl.CommandContext{
|
//cmdController.AddCommands(&commandctrl.CommandList{
|
||||||
// Commands: map[string]commandctrl.Command{
|
// Commands: map[string]commandctrl.Command{
|
||||||
// "cd": func(args []string) tea.Cmd {
|
// "cd": func(args []string) tea.Cmd {
|
||||||
// return ctrl.ChangePrefix(args[0])
|
// return ctrl.ChangePrefix(args[0])
|
||||||
|
|
|
@ -48,7 +48,7 @@ func main() {
|
||||||
ctrl := controllers.New(service)
|
ctrl := controllers.New(service)
|
||||||
|
|
||||||
cmdController := commandctrl.NewCommandController()
|
cmdController := commandctrl.NewCommandController()
|
||||||
cmdController.AddCommands(&commandctrl.CommandContext{
|
cmdController.AddCommands(&commandctrl.CommandList{
|
||||||
Commands: map[string]commandctrl.Command{
|
Commands: map[string]commandctrl.Command{
|
||||||
"cd": func(args []string) tea.Msg {
|
"cd": func(args []string) tea.Msg {
|
||||||
return ctrl.ChangePrefix(args[0])
|
return ctrl.ChangePrefix(args[0])
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package commandctrl
|
package commandctrl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lmika/audax/internal/common/ui/events"
|
"github.com/lmika/audax/internal/common/ui/events"
|
||||||
|
@ -11,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommandController struct {
|
type CommandController struct {
|
||||||
commandList *CommandContext
|
commandList *CommandList
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommandController() *CommandController {
|
func NewCommandController() *CommandController {
|
||||||
|
@ -20,7 +24,7 @@ func NewCommandController() *CommandController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandController) AddCommands(ctx *CommandContext) {
|
func (c *CommandController) AddCommands(ctx *CommandList) {
|
||||||
ctx.parent = c.commandList
|
ctx.parent = c.commandList
|
||||||
c.commandList = ctx
|
c.commandList = ctx
|
||||||
}
|
}
|
||||||
|
@ -35,6 +39,10 @@ func (c *CommandController) Prompt() tea.Msg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandController) Execute(commandInput string) tea.Msg {
|
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)
|
input := strings.TrimSpace(commandInput)
|
||||||
if input == "" {
|
if input == "" {
|
||||||
return nil
|
return nil
|
||||||
|
@ -43,31 +51,65 @@ func (c *CommandController) Execute(commandInput string) tea.Msg {
|
||||||
tokens := shellwords.Split(input)
|
tokens := shellwords.Split(input)
|
||||||
command := c.lookupCommand(tokens[0])
|
command := c.lookupCommand(tokens[0])
|
||||||
if command == nil {
|
if command == nil {
|
||||||
log.Println("No such command: ", tokens)
|
|
||||||
return events.Error(errors.New("no such command: " + tokens[0]))
|
return events.Error(errors.New("no such command: " + tokens[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return command(tokens[1:])
|
return command(ctx, tokens[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandController) Alias(commandName string) Command {
|
func (c *CommandController) Alias(commandName string) Command {
|
||||||
return func(args []string) tea.Msg {
|
return func(ctx ExecContext, args []string) tea.Msg {
|
||||||
command := c.lookupCommand(commandName)
|
command := c.lookupCommand(commandName)
|
||||||
if command == nil {
|
if command == nil {
|
||||||
log.Println("No such command: ", commandName)
|
|
||||||
return events.Error(errors.New("no such command: " + commandName))
|
return events.Error(errors.New("no such command: " + commandName))
|
||||||
}
|
}
|
||||||
|
|
||||||
return command(args)
|
return command(ctx, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandController) lookupCommand(name string) Command {
|
func (c *CommandController) lookupCommand(name string) Command {
|
||||||
for ctx := c.commandList; ctx != nil; ctx = ctx.parent {
|
for ctx := c.commandList; ctx != nil; ctx = ctx.parent {
|
||||||
log.Printf("Looking in command list: %v", c.commandList)
|
|
||||||
if cmd, ok := ctx.Commands[name]; ok {
|
if cmd, ok := ctx.Commands[name]; ok {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,6 @@
|
||||||
package commandctrl
|
package commandctrl
|
||||||
|
|
||||||
import "context"
|
type ExecContext struct {
|
||||||
|
// FromFile is true if the command is executed as part of a command
|
||||||
type commandArgContextKeyType struct{}
|
FromFile bool
|
||||||
|
|
||||||
var commandArgContextKey = commandArgContextKeyType{}
|
|
||||||
|
|
||||||
func WithCommandArgs(ctx context.Context, args []string) context.Context {
|
|
||||||
return context.WithValue(ctx, commandArgContextKey, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CommandArgs(ctx context.Context) []string {
|
|
||||||
args, _ := ctx.Value(commandArgContextKey).([]string)
|
|
||||||
return args
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ package commandctrl
|
||||||
|
|
||||||
import tea "github.com/charmbracelet/bubbletea"
|
import tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
type Command func(args []string) tea.Msg
|
type Command func(ctx ExecContext, args []string) tea.Msg
|
||||||
|
|
||||||
func NoArgCommand(cmd tea.Cmd) Command {
|
func NoArgCommand(cmd tea.Cmd) Command {
|
||||||
return func(args []string) tea.Msg {
|
return func(ctx ExecContext, args []string) tea.Msg {
|
||||||
return cmd()
|
return cmd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandContext struct {
|
type CommandList struct {
|
||||||
Commands map[string]Command
|
Commands map[string]Command
|
||||||
|
|
||||||
parent *CommandContext
|
parent *CommandList
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@ func NewKeyBindingController(service *keybindings.Service) *KeyBindingController
|
||||||
return &KeyBindingController{service: service}
|
return &KeyBindingController{service: service}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kb *KeyBindingController) Rebind(bindingName string, newKey string) tea.Msg {
|
func (kb *KeyBindingController) Rebind(bindingName string, newKey string, force bool) tea.Msg {
|
||||||
err := kb.service.Rebind(bindingName, newKey, false)
|
err := kb.service.Rebind(bindingName, newKey, force)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return events.SetStatus(fmt.Sprintf("Binding '%v' now bound to '%v'", bindingName, newKey))
|
return events.SetStatus(fmt.Sprintf("Binding '%v' now bound to '%v'", bindingName, newKey))
|
||||||
|
} else if force {
|
||||||
|
return events.Error(errors.Wrapf(err, "cannot bind '%v' to '%v'", bindingName, newKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyAlreadyBoundErr keybindings.KeyAlreadyBoundError
|
var keyAlreadyBoundErr keybindings.KeyAlreadyBoundError
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,6 +32,8 @@ const (
|
||||||
ViewModeTableOnly = 4
|
ViewModeTableOnly = 4
|
||||||
|
|
||||||
ViewModeCount = 5
|
ViewModeCount = 5
|
||||||
|
|
||||||
|
initRCFilename = "$HOME/.config/audax/dynamo-browse/init.rc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
|
@ -69,17 +72,17 @@ func NewModel(
|
||||||
dialogPrompt := dialogprompt.New(statusAndPrompt)
|
dialogPrompt := dialogprompt.New(statusAndPrompt)
|
||||||
tableSelect := tableselect.New(dialogPrompt, uiStyles)
|
tableSelect := tableselect.New(dialogPrompt, uiStyles)
|
||||||
|
|
||||||
cc.AddCommands(&commandctrl.CommandContext{
|
cc.AddCommands(&commandctrl.CommandList{
|
||||||
Commands: map[string]commandctrl.Command{
|
Commands: map[string]commandctrl.Command{
|
||||||
"quit": commandctrl.NoArgCommand(tea.Quit),
|
"quit": commandctrl.NoArgCommand(tea.Quit),
|
||||||
"table": func(args []string) tea.Msg {
|
"table": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return rc.ListTables()
|
return rc.ListTables()
|
||||||
} else {
|
} else {
|
||||||
return rc.ScanTable(args[0])
|
return rc.ScanTable(args[0])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"export": func(args []string) tea.Msg {
|
"export": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return events.Error(errors.New("expected filename"))
|
return events.Error(errors.New("expected filename"))
|
||||||
}
|
}
|
||||||
|
@ -90,7 +93,7 @@ func NewModel(
|
||||||
|
|
||||||
// TEMP
|
// TEMP
|
||||||
"new-item": commandctrl.NoArgCommand(wc.NewItem),
|
"new-item": commandctrl.NoArgCommand(wc.NewItem),
|
||||||
"set-attr": func(args []string) tea.Msg {
|
"set-attr": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return events.Error(errors.New("expected field"))
|
return events.Error(errors.New("expected field"))
|
||||||
}
|
}
|
||||||
|
@ -114,28 +117,35 @@ func NewModel(
|
||||||
|
|
||||||
return wc.SetAttributeValue(dtv.SelectedItemIndex(), itemType, args[0])
|
return wc.SetAttributeValue(dtv.SelectedItemIndex(), itemType, args[0])
|
||||||
},
|
},
|
||||||
"del-attr": func(args []string) tea.Msg {
|
"del-attr": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return events.Error(errors.New("expected field"))
|
return events.Error(errors.New("expected field"))
|
||||||
}
|
}
|
||||||
return wc.DeleteAttribute(dtv.SelectedItemIndex(), args[0])
|
return wc.DeleteAttribute(dtv.SelectedItemIndex(), args[0])
|
||||||
},
|
},
|
||||||
|
|
||||||
"put": func(args []string) tea.Msg {
|
"put": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
return wc.PutItems()
|
return wc.PutItems()
|
||||||
},
|
},
|
||||||
"touch": func(args []string) tea.Msg {
|
"touch": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
return wc.TouchItem(dtv.SelectedItemIndex())
|
return wc.TouchItem(dtv.SelectedItemIndex())
|
||||||
},
|
},
|
||||||
"noisy-touch": func(args []string) tea.Msg {
|
"noisy-touch": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
return wc.NoisyTouchItem(dtv.SelectedItemIndex())
|
return wc.NoisyTouchItem(dtv.SelectedItemIndex())
|
||||||
},
|
},
|
||||||
|
|
||||||
"rebind": func(args []string) tea.Msg {
|
"echo": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
if len(args) != 2 {
|
s := new(strings.Builder)
|
||||||
return events.Error(errors.New("expected: name newKey"))
|
for _, arg := range args {
|
||||||
|
s.WriteString(arg)
|
||||||
}
|
}
|
||||||
return keyBindingController.Rebind(args[0], args[1])
|
return events.SetStatus(s.String())
|
||||||
|
},
|
||||||
|
"rebind": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return events.Error(errors.New("expected: bindingName newKey"))
|
||||||
|
}
|
||||||
|
return keyBindingController.Rebind(args[0], args[1], ctx.FromFile)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Aliases
|
// Aliases
|
||||||
|
@ -164,6 +174,12 @@ func NewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
func (m Model) Init() tea.Cmd {
|
||||||
|
// TODO: this should probably be moved somewhere else
|
||||||
|
rcFilename := os.ExpandEnv(initRCFilename)
|
||||||
|
if err := m.commandController.ExecuteFile(rcFilename); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
return m.tableReadController.Init
|
return m.tableReadController.Init
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ func NewModel(controller *controllers.SSMController, cmdController *commandctrl.
|
||||||
statusAndPrompt := statusandprompt.New(
|
statusAndPrompt := statusandprompt.New(
|
||||||
layout.NewVBox(layout.LastChildFixedAt(17), ssmList, ssmdDetails), "", defaultStyles.StatusAndPrompt)
|
layout.NewVBox(layout.LastChildFixedAt(17), ssmList, ssmdDetails), "", defaultStyles.StatusAndPrompt)
|
||||||
|
|
||||||
cmdController.AddCommands(&commandctrl.CommandContext{
|
cmdController.AddCommands(&commandctrl.CommandList{
|
||||||
Commands: map[string]commandctrl.Command{
|
Commands: map[string]commandctrl.Command{
|
||||||
"clone": func(args []string) tea.Msg {
|
"clone": func(args []string) tea.Msg {
|
||||||
if currentParam := ssmList.CurrentParameter(); currentParam != nil {
|
if currentParam := ssmList.CurrentParameter(); currentParam != nil {
|
||||||
|
|
Loading…
Reference in a new issue