From 5b6bf1f0aedcca779261849b2b38d352b6457255 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Thu, 18 Aug 2022 21:39:13 +1000 Subject: [PATCH] ctrlret: replaced return types of controllers from tea.Cmd to tea.Msg This dramatically cuts downs the number of closures. --- cmd/ssm-browse/main.go | 2 +- internal/common/ui/commandctrl/commandctrl.go | 22 +- .../common/ui/commandctrl/commandctrl_test.go | 4 +- internal/common/ui/commandctrl/types.go | 8 +- internal/common/ui/events/commands.go | 30 +- internal/common/ui/events/errors.go | 2 +- .../dynamo-browse/controllers/commands.go | 4 +- internal/dynamo-browse/controllers/events.go | 2 +- .../dynamo-browse/controllers/tableread.go | 248 ++++---- .../controllers/tableread_test.go | 34 +- .../dynamo-browse/controllers/tablewrite.go | 564 ++++++++---------- internal/dynamo-browse/ui/model.go | 42 +- .../ui/teamodels/statusandprompt/model.go | 2 +- .../ui/teamodels/tableselect/model.go | 2 +- internal/slog-view/ui/model.go | 2 +- .../ssm-browse/controllers/ssmcontroller.go | 56 +- internal/ssm-browse/ui/model.go | 10 +- 17 files changed, 472 insertions(+), 562 deletions(-) diff --git a/cmd/ssm-browse/main.go b/cmd/ssm-browse/main.go index a09ec07..c5e46c9 100644 --- a/cmd/ssm-browse/main.go +++ b/cmd/ssm-browse/main.go @@ -50,7 +50,7 @@ func main() { cmdController := commandctrl.NewCommandController() cmdController.AddCommands(&commandctrl.CommandContext{ Commands: map[string]commandctrl.Command{ - "cd": func(args []string) tea.Cmd { + "cd": func(args []string) tea.Msg { return ctrl.ChangePrefix(args[0]) }, }, diff --git a/internal/common/ui/commandctrl/commandctrl.go b/internal/common/ui/commandctrl/commandctrl.go index e5c84e3..f26ab6c 100644 --- a/internal/common/ui/commandctrl/commandctrl.go +++ b/internal/common/ui/commandctrl/commandctrl.go @@ -25,18 +25,16 @@ func (c *CommandController) AddCommands(ctx *CommandContext) { c.commandList = ctx } -func (c *CommandController) Prompt() tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: ":", - OnDone: func(value string) tea.Cmd { - return c.Execute(value) - }, - } +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.Cmd { +func (c *CommandController) Execute(commandInput string) tea.Msg { input := strings.TrimSpace(commandInput) if input == "" { return nil @@ -46,18 +44,18 @@ func (c *CommandController) Execute(commandInput string) tea.Cmd { command := c.lookupCommand(tokens[0]) if command == nil { log.Println("No such command: ", tokens) - return events.SetError(errors.New("no such command: " + tokens[0])) + return events.Error(errors.New("no such command: " + tokens[0])) } return command(tokens[1:]) } func (c *CommandController) Alias(commandName string) Command { - return func(args []string) tea.Cmd { + return func(args []string) tea.Msg { command := c.lookupCommand(commandName) if command == nil { log.Println("No such command: ", commandName) - return events.SetError(errors.New("no such command: " + commandName)) + return events.Error(errors.New("no such command: " + commandName)) } return command(args) diff --git a/internal/common/ui/commandctrl/commandctrl_test.go b/internal/common/ui/commandctrl/commandctrl_test.go index 0598621..e842c39 100644 --- a/internal/common/ui/commandctrl/commandctrl_test.go +++ b/internal/common/ui/commandctrl/commandctrl_test.go @@ -1,10 +1,10 @@ package commandctrl_test import ( + "github.com/lmika/audax/internal/common/ui/events" "testing" "github.com/lmika/audax/internal/common/ui/commandctrl" - "github.com/lmika/audax/internal/common/ui/events" "github.com/stretchr/testify/assert" ) @@ -12,7 +12,7 @@ func TestCommandController_Prompt(t *testing.T) { t.Run("prompt user for a command", func(t *testing.T) { cmd := commandctrl.NewCommandController() - res := cmd.Prompt()() + res := cmd.Prompt() promptForInputMsg, ok := res.(events.PromptForInputMsg) assert.True(t, ok) diff --git a/internal/common/ui/commandctrl/types.go b/internal/common/ui/commandctrl/types.go index 0cf1a9e..c5f6f74 100644 --- a/internal/common/ui/commandctrl/types.go +++ b/internal/common/ui/commandctrl/types.go @@ -2,16 +2,16 @@ package commandctrl import tea "github.com/charmbracelet/bubbletea" -type Command func(args []string) tea.Cmd +type Command func(args []string) tea.Msg func NoArgCommand(cmd tea.Cmd) Command { - return func(args []string) tea.Cmd { - return cmd + return func(args []string) tea.Msg { + return cmd() } } type CommandContext struct { Commands map[string]Command - parent *CommandContext + parent *CommandContext } diff --git a/internal/common/ui/events/commands.go b/internal/common/ui/events/commands.go index ef82c2f..8aca1a7 100644 --- a/internal/common/ui/events/commands.go +++ b/internal/common/ui/events/commands.go @@ -10,29 +10,19 @@ func Error(err error) tea.Msg { return ErrorMsg(err) } -func SetError(err error) tea.Cmd { - return func() tea.Msg { - return Error(err) +func SetStatus(msg string) tea.Msg { + return StatusMsg(msg) +} + +func PromptForInput(prompt string, onDone func(value string) tea.Msg) tea.Msg { + return PromptForInputMsg{ + Prompt: prompt, + OnDone: onDone, } } -func SetStatus(msg string) tea.Cmd { - return func() tea.Msg { - return StatusMsg(msg) - } -} - -func PromptForInput(prompt string, onDone func(value string) tea.Cmd) tea.Cmd { - return func() tea.Msg { - return PromptForInputMsg{ - Prompt: prompt, - OnDone: onDone, - } - } -} - -func Confirm(prompt string, onYes func() tea.Cmd) tea.Cmd { - return PromptForInput(prompt, func(value string) tea.Cmd { +func Confirm(prompt string, onYes func() tea.Msg) tea.Msg { + return PromptForInput(prompt, func(value string) tea.Msg { if value == "y" { return onYes() } diff --git a/internal/common/ui/events/errors.go b/internal/common/ui/events/errors.go index 9aa3388..fd05570 100644 --- a/internal/common/ui/events/errors.go +++ b/internal/common/ui/events/errors.go @@ -16,5 +16,5 @@ type ModeMessage string // PromptForInput indicates that the context is requesting a line of input type PromptForInputMsg struct { Prompt string - OnDone func(value string) tea.Cmd + OnDone func(value string) tea.Msg } diff --git a/internal/dynamo-browse/controllers/commands.go b/internal/dynamo-browse/controllers/commands.go index dd94a93..16390e2 100644 --- a/internal/dynamo-browse/controllers/commands.go +++ b/internal/dynamo-browse/controllers/commands.go @@ -15,9 +15,9 @@ func (ps *promptSequence) next() tea.Msg { if len(ps.receivedValues) < len(ps.prompts) { return events.PromptForInputMsg{ Prompt: ps.prompts[len(ps.receivedValues)], - OnDone: func(value string) tea.Cmd { + OnDone: func(value string) tea.Msg { ps.receivedValues = append(ps.receivedValues, value) - return ps.next + return ps.next() }, } } diff --git a/internal/dynamo-browse/controllers/events.go b/internal/dynamo-browse/controllers/events.go index cf957b1..63c79a6 100644 --- a/internal/dynamo-browse/controllers/events.go +++ b/internal/dynamo-browse/controllers/events.go @@ -46,7 +46,7 @@ type SetReadWrite struct { type PromptForTableMsg struct { Tables []string - OnSelected func(tableName string) tea.Cmd + OnSelected func(tableName string) tea.Msg } type ResultSetUpdated struct { diff --git a/internal/dynamo-browse/controllers/tableread.go b/internal/dynamo-browse/controllers/tableread.go index a5caa5a..62a5777 100644 --- a/internal/dynamo-browse/controllers/tableread.go +++ b/internal/dynamo-browse/controllers/tableread.go @@ -35,7 +35,7 @@ func NewTableReadController(state *State, tableService TableReadService, workspa } // Init does an initial scan of the table. If no table is specified, it prompts for a table, then does a scan. -func (c *TableReadController) Init() tea.Cmd { +func (c *TableReadController) Init() tea.Msg { if c.tableName == "" { return c.ListTables() } else { @@ -43,51 +43,43 @@ func (c *TableReadController) Init() tea.Cmd { } } -func (c *TableReadController) ListTables() tea.Cmd { - return func() tea.Msg { - tables, err := c.tableService.ListTables(context.Background()) - if err != nil { - return events.Error(err) - } +func (c *TableReadController) ListTables() tea.Msg { + tables, err := c.tableService.ListTables(context.Background()) + if err != nil { + return events.Error(err) + } - return PromptForTableMsg{ - Tables: tables, - OnSelected: func(tableName string) tea.Cmd { - return c.ScanTable(tableName) - }, - } + return PromptForTableMsg{ + Tables: tables, + OnSelected: func(tableName string) tea.Msg { + return c.ScanTable(tableName) + }, } } -func (c *TableReadController) ScanTable(name string) tea.Cmd { - return func() tea.Msg { - ctx := context.Background() +func (c *TableReadController) ScanTable(name string) tea.Msg { + ctx := context.Background() - tableInfo, err := c.tableService.Describe(ctx, name) - if err != nil { - return events.Error(errors.Wrapf(err, "cannot describe %v", c.tableName)) - } - - resultSet, err := c.tableService.Scan(ctx, tableInfo) - if err != nil { - return events.Error(err) - } - resultSet = c.tableService.Filter(resultSet, c.state.Filter()) - - return c.setResultSetAndFilter(resultSet, c.state.Filter(), true) + tableInfo, err := c.tableService.Describe(ctx, name) + if err != nil { + return events.Error(errors.Wrapf(err, "cannot describe %v", c.tableName)) } + + resultSet, err := c.tableService.Scan(ctx, tableInfo) + if err != nil { + return events.Error(err) + } + resultSet = c.tableService.Filter(resultSet, c.state.Filter()) + + return c.setResultSetAndFilter(resultSet, c.state.Filter(), true) } -func (c *TableReadController) PromptForQuery() tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: "query: ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - return c.runQuery(c.state.ResultSet().TableInfo, value, "", true) - } - }, - } +func (c *TableReadController) PromptForQuery() tea.Msg { + return events.PromptForInputMsg{ + Prompt: "query: ", + OnDone: func(value string) tea.Msg { + return c.runQuery(c.state.ResultSet().TableInfo, value, "", true) + }, } } @@ -107,7 +99,7 @@ func (c *TableReadController) runQuery(tableInfo *models.TableInfo, query, newFi expr, err := queryexpr.Parse(query) if err != nil { - return events.SetError(err) + return events.Error(err) } return c.doIfNoneDirty(func() tea.Msg { @@ -135,58 +127,54 @@ func (c *TableReadController) doIfNoneDirty(cmd tea.Cmd) tea.Msg { return events.PromptForInputMsg{ Prompt: "reset modified items? ", - OnDone: func(value string) tea.Cmd { + OnDone: func(value string) tea.Msg { if value != "y" { return events.SetStatus("operation aborted") } - return cmd + return cmd() }, } } -func (c *TableReadController) Rescan() tea.Cmd { - return func() tea.Msg { - return c.doIfNoneDirty(func() tea.Msg { - resultSet := c.state.ResultSet() - return c.doScan(context.Background(), resultSet, resultSet.Query, true) - }) - } +func (c *TableReadController) Rescan() tea.Msg { + return c.doIfNoneDirty(func() tea.Msg { + resultSet := c.state.ResultSet() + return c.doScan(context.Background(), resultSet, resultSet.Query, true) + }) } -func (c *TableReadController) ExportCSV(filename string) tea.Cmd { - return func() tea.Msg { - resultSet := c.state.ResultSet() - if resultSet == nil { - return events.Error(errors.New("no result set")) - } - - f, err := os.Create(filename) - if err != nil { - return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) - } - defer f.Close() - - cw := csv.NewWriter(f) - defer cw.Flush() - - columns := resultSet.Columns() - if err := cw.Write(columns); err != nil { - return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) - } - - row := make([]string, len(columns)) - for _, item := range resultSet.Items() { - for i, col := range columns { - row[i], _ = item.AttributeValueAsString(col) - } - if err := cw.Write(row); err != nil { - return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) - } - } - - return nil +func (c *TableReadController) ExportCSV(filename string) tea.Msg { + resultSet := c.state.ResultSet() + if resultSet == nil { + return events.Error(errors.New("no result set")) } + + f, err := os.Create(filename) + if err != nil { + return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) + } + defer f.Close() + + cw := csv.NewWriter(f) + defer cw.Flush() + + columns := resultSet.Columns() + if err := cw.Write(columns); err != nil { + return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) + } + + row := make([]string, len(columns)) + for _, item := range resultSet.Items() { + for i, col := range columns { + row[i], _ = item.AttributeValueAsString(col) + } + if err := cw.Write(row); err != nil { + return events.Error(errors.Wrapf(err, "cannot export to '%v'", filename)) + } + } + + return nil } func (c *TableReadController) doScan(ctx context.Context, resultSet *models.ResultSet, query models.Queryable, pushBackstack bool) tea.Msg { @@ -211,66 +199,58 @@ func (c *TableReadController) setResultSetAndFilter(resultSet *models.ResultSet, return c.state.buildNewResultSetMessage("") } -func (c *TableReadController) Unmark() tea.Cmd { - return func() tea.Msg { - c.state.withResultSet(func(resultSet *models.ResultSet) { - for i := range resultSet.Items() { - resultSet.SetMark(i, false) - } - }) - return ResultSetUpdated{} - } -} - -func (c *TableReadController) Filter() tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: "filter: ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - resultSet := c.state.ResultSet() - newResultSet := c.tableService.Filter(resultSet, value) - - return c.setResultSetAndFilter(newResultSet, value, true) - } - }, +func (c *TableReadController) Unmark() tea.Msg { + c.state.withResultSet(func(resultSet *models.ResultSet) { + for i := range resultSet.Items() { + resultSet.SetMark(i, false) } + }) + return ResultSetUpdated{} +} + +func (c *TableReadController) Filter() tea.Msg { + return events.PromptForInputMsg{ + Prompt: "filter: ", + OnDone: func(value string) tea.Msg { + resultSet := c.state.ResultSet() + newResultSet := c.tableService.Filter(resultSet, value) + + return c.setResultSetAndFilter(newResultSet, value, true) + }, } } -func (c *TableReadController) ViewBack() tea.Cmd { - return func() tea.Msg { - viewSnapshot, err := c.workspaceService.PopSnapshot() +func (c *TableReadController) ViewBack() tea.Msg { + viewSnapshot, err := c.workspaceService.PopSnapshot() + if err != nil { + return events.Error(err) + } else if viewSnapshot == nil { + return events.StatusMsg("Backstack is empty") + } + + currentResultSet := c.state.ResultSet() + + var currentQueryExpr string + if currentResultSet.Query != nil { + currentQueryExpr = currentResultSet.Query.String() + } + + if viewSnapshot.TableName == currentResultSet.TableInfo.Name && viewSnapshot.Query == currentQueryExpr { + log.Printf("backstack: setting filter to '%v'", viewSnapshot.Filter) + + newResultSet := c.tableService.Filter(currentResultSet, viewSnapshot.Filter) + return c.setResultSetAndFilter(newResultSet, viewSnapshot.Filter, false) + } + + tableInfo := currentResultSet.TableInfo + if viewSnapshot.TableName != currentResultSet.TableInfo.Name { + tableInfo, err = c.tableService.Describe(context.Background(), viewSnapshot.TableName) if err != nil { return events.Error(err) - } else if viewSnapshot == nil { - return events.StatusMsg("Backstack is empty") } - - currentResultSet := c.state.ResultSet() - - var currentQueryExpr string - if currentResultSet.Query != nil { - currentQueryExpr = currentResultSet.Query.String() - } - - if viewSnapshot.TableName == currentResultSet.TableInfo.Name && viewSnapshot.Query == currentQueryExpr { - log.Printf("backstack: setting filter to '%v'", viewSnapshot.Filter) - - newResultSet := c.tableService.Filter(currentResultSet, viewSnapshot.Filter) - return c.setResultSetAndFilter(newResultSet, viewSnapshot.Filter, false) - } - - tableInfo := currentResultSet.TableInfo - if viewSnapshot.TableName != currentResultSet.TableInfo.Name { - tableInfo, err = c.tableService.Describe(context.Background(), viewSnapshot.TableName) - if err != nil { - return events.Error(err) - } - } - - log.Printf("backstack: running query: table = '%v', query = '%v', filter = '%v'", - tableInfo.Name, viewSnapshot.Query, viewSnapshot.Filter) - return c.runQuery(tableInfo, viewSnapshot.Query, viewSnapshot.Filter, false) } + + log.Printf("backstack: running query: table = '%v', query = '%v', filter = '%v'", + tableInfo.Name, viewSnapshot.Query, viewSnapshot.Filter) + return c.runQuery(tableInfo, viewSnapshot.Query, viewSnapshot.Filter, false) } diff --git a/internal/dynamo-browse/controllers/tableread_test.go b/internal/dynamo-browse/controllers/tableread_test.go index e2f3329..9784040 100644 --- a/internal/dynamo-browse/controllers/tableread_test.go +++ b/internal/dynamo-browse/controllers/tableread_test.go @@ -29,8 +29,7 @@ func TestTableReadController_InitTable(t *testing.T) { t.Run("should prompt for table if no table name provided", func(t *testing.T) { readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "") - cmd := readController.Init() - event := cmd() + event := readController.Init() assert.IsType(t, controllers.PromptForTableMsg{}, event) }) @@ -38,8 +37,7 @@ func TestTableReadController_InitTable(t *testing.T) { t.Run("should scan table if table name provided", func(t *testing.T) { readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "") - cmd := readController.Init() - event := cmd() + event := readController.Init() assert.IsType(t, controllers.PromptForTableMsg{}, event) }) @@ -56,13 +54,11 @@ func TestTableReadController_ListTables(t *testing.T) { readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "") t.Run("returns a list of tables", func(t *testing.T) { - cmd := readController.ListTables() - event := cmd().(controllers.PromptForTableMsg) + event := readController.ListTables().(controllers.PromptForTableMsg) assert.Equal(t, []string{"alpha-table", "bravo-table"}, event.Tables) - selectedCmd := event.OnSelected("alpha-table") - selectedEvent := selectedCmd() + selectedEvent := event.OnSelected("alpha-table") resultSet := selectedEvent.(controllers.NewResultSet) assert.Equal(t, "alpha-table", resultSet.ResultSet.TableInfo.Name) @@ -208,9 +204,7 @@ func testWorkspace(t *testing.T) *workspaces.Workspace { return ws } -func invokeCommand(t *testing.T, cmd tea.Cmd) tea.Msg { - msg := cmd() - +func invokeCommand(t *testing.T, msg tea.Msg) tea.Msg { err, isErr := msg.(events.ErrorMsg) if isErr { assert.Fail(t, fmt.Sprintf("expected no error but got one: %v", err)) @@ -218,9 +212,7 @@ func invokeCommand(t *testing.T, cmd tea.Cmd) tea.Msg { return msg } -func invokeCommandWithPrompt(t *testing.T, cmd tea.Cmd, promptValue string) { - msg := cmd() - +func invokeCommandWithPrompt(t *testing.T, msg tea.Msg, promptValue string) { pi, isPi := msg.(events.PromptForInputMsg) if !isPi { assert.Fail(t, fmt.Sprintf("expected prompt for input but didn't get one")) @@ -229,22 +221,18 @@ func invokeCommandWithPrompt(t *testing.T, cmd tea.Cmd, promptValue string) { invokeCommand(t, pi.OnDone(promptValue)) } -func invokeCommandWithPrompts(t *testing.T, cmd tea.Cmd, promptValues ...string) { - msg := cmd() - +func invokeCommandWithPrompts(t *testing.T, msg tea.Msg, promptValues ...string) { for _, promptValue := range promptValues { pi, isPi := msg.(events.PromptForInputMsg) if !isPi { - assert.Fail(t, fmt.Sprintf("expected prompt for input but didn't get one")) + assert.Fail(t, fmt.Sprintf("expected prompt for input but didn't get one: %T", msg)) } msg = invokeCommand(t, pi.OnDone(promptValue)) } } -func invokeCommandWithPromptsExpectingError(t *testing.T, cmd tea.Cmd, promptValues ...string) { - msg := cmd() - +func invokeCommandWithPromptsExpectingError(t *testing.T, msg tea.Msg, promptValues ...string) { for _, promptValue := range promptValues { pi, isPi := msg.(events.PromptForInputMsg) if !isPi { @@ -258,9 +246,7 @@ func invokeCommandWithPromptsExpectingError(t *testing.T, cmd tea.Cmd, promptVal assert.True(t, isErr) } -func invokeCommandExpectingError(t *testing.T, cmd tea.Cmd) { - msg := cmd() - +func invokeCommandExpectingError(t *testing.T, msg tea.Msg) { _, isErr := msg.(events.ErrorMsg) assert.True(t, isErr) } diff --git a/internal/dynamo-browse/controllers/tablewrite.go b/internal/dynamo-browse/controllers/tablewrite.go index 5f79d7d..c376d3f 100644 --- a/internal/dynamo-browse/controllers/tablewrite.go +++ b/internal/dynamo-browse/controllers/tablewrite.go @@ -27,50 +27,46 @@ func NewTableWriteController(state *State, tableService *tables.Service, tableRe } } -func (twc *TableWriteController) ToggleMark(idx int) tea.Cmd { - return func() tea.Msg { - twc.state.withResultSet(func(resultSet *models.ResultSet) { - resultSet.SetMark(idx, !resultSet.Marked(idx)) - }) +func (twc *TableWriteController) ToggleMark(idx int) tea.Msg { + twc.state.withResultSet(func(resultSet *models.ResultSet) { + resultSet.SetMark(idx, !resultSet.Marked(idx)) + }) - return ResultSetUpdated{} - } + return ResultSetUpdated{} } -func (twc *TableWriteController) NewItem() tea.Cmd { - return func() tea.Msg { - // Work out which keys we need to prompt for - rs := twc.state.ResultSet() +func (twc *TableWriteController) NewItem() tea.Msg { + // Work out which keys we need to prompt for + rs := twc.state.ResultSet() - keyPrompts := &promptSequence{ - prompts: []string{rs.TableInfo.Keys.PartitionKey + ": "}, - } - if rs.TableInfo.Keys.SortKey != "" { - keyPrompts.prompts = append(keyPrompts.prompts, rs.TableInfo.Keys.SortKey+": ") - } - keyPrompts.onAllDone = func(values []string) tea.Msg { - twc.state.withResultSet(func(set *models.ResultSet) { - newItem := models.Item{} + keyPrompts := &promptSequence{ + prompts: []string{rs.TableInfo.Keys.PartitionKey + ": "}, + } + if rs.TableInfo.Keys.SortKey != "" { + keyPrompts.prompts = append(keyPrompts.prompts, rs.TableInfo.Keys.SortKey+": ") + } + keyPrompts.onAllDone = func(values []string) tea.Msg { + twc.state.withResultSet(func(set *models.ResultSet) { + newItem := models.Item{} - // TODO: deal with keys of different type - newItem[rs.TableInfo.Keys.PartitionKey] = &types.AttributeValueMemberS{Value: values[0]} - if len(values) == 2 { - newItem[rs.TableInfo.Keys.SortKey] = &types.AttributeValueMemberS{Value: values[1]} - } + // TODO: deal with keys of different type + newItem[rs.TableInfo.Keys.PartitionKey] = &types.AttributeValueMemberS{Value: values[0]} + if len(values) == 2 { + newItem[rs.TableInfo.Keys.SortKey] = &types.AttributeValueMemberS{Value: values[1]} + } - set.AddNewItem(newItem, models.ItemAttribute{ - New: true, - Dirty: true, - }) + set.AddNewItem(newItem, models.ItemAttribute{ + New: true, + Dirty: true, }) - return twc.state.buildNewResultSetMessage("New item added") - } - - return keyPrompts.next() + }) + return twc.state.buildNewResultSetMessage("New item added") } + + return keyPrompts.next() } -func (twc *TableWriteController) SetAttributeValue(idx int, itemType models.ItemType, key string) tea.Cmd { +func (twc *TableWriteController) SetAttributeValue(idx int, itemType models.ItemType, key string) tea.Msg { apPath := newAttrPath(key) var attrValue types.AttributeValue @@ -78,7 +74,7 @@ func (twc *TableWriteController) SetAttributeValue(idx int, itemType models.Item attrValue, err = apPath.follow(set.Items()[idx]) return err }); err != nil { - return events.SetError(err) + return events.Error(err) } switch itemType { @@ -91,7 +87,7 @@ func (twc *TableWriteController) SetAttributeValue(idx int, itemType models.Item case *types.AttributeValueMemberBOOL: return twc.setBoolValue(idx, apPath) default: - return events.SetError(errors.New("attribute type for key must be set")) + return events.Error(errors.New("attribute type for key must be set")) } case models.StringItemType: return twc.setStringValue(idx, apPath) @@ -102,35 +98,31 @@ func (twc *TableWriteController) SetAttributeValue(idx int, itemType models.Item case models.NullItemType: return twc.setNullValue(idx, apPath) default: - return events.SetError(errors.New("unsupported attribute type")) + return events.Error(errors.New("unsupported attribute type")) } } -func (twc *TableWriteController) setStringValue(idx int, attr attrPath) tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: "string value: ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { - if err := attr.setAt(item, &types.AttributeValueMemberS{Value: value}); err != nil { - return err - } - set.SetDirty(idx, true) - return nil - }); err != nil { - return err - } - set.RefreshColumns() - return nil - }); err != nil { - return events.Error(err) +func (twc *TableWriteController) setStringValue(idx int, attr attrPath) tea.Msg { + return events.PromptForInputMsg{ + Prompt: "string value: ", + OnDone: func(value string) tea.Msg { + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { + if err := attr.setAt(item, &types.AttributeValueMemberS{Value: value}); err != nil { + return err } - return ResultSetUpdated{} + set.SetDirty(idx, true) + return nil + }); err != nil { + return err } - }, - } + set.RefreshColumns() + return nil + }); err != nil { + return events.Error(err) + } + return ResultSetUpdated{} + }, } } @@ -147,294 +139,262 @@ func (twc *TableWriteController) applyToItems(rs *models.ResultSet, selectedInde return applyFn(selectedIndex, rs.Items()[selectedIndex]) } -func (twc *TableWriteController) setNumberValue(idx int, attr attrPath) tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: "number value: ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { - if err := attr.setAt(item, &types.AttributeValueMemberN{Value: value}); err != nil { - return err - } - set.SetDirty(idx, true) - return nil - }); err != nil { - return err - } - set.RefreshColumns() - return nil - }); err != nil { - return events.Error(err) +func (twc *TableWriteController) setNumberValue(idx int, attr attrPath) tea.Msg { + return events.PromptForInputMsg{ + Prompt: "number value: ", + OnDone: func(value string) tea.Msg { + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { + if err := attr.setAt(item, &types.AttributeValueMemberN{Value: value}); err != nil { + return err } - return ResultSetUpdated{} - } - }, - } - } -} - -func (twc *TableWriteController) setBoolValue(idx int, attr attrPath) tea.Cmd { - return func() tea.Msg { - return events.PromptForInputMsg{ - Prompt: "bool value: ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - b, err := strconv.ParseBool(value) - if err != nil { - return events.Error(err) - } - - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { - if err := attr.setAt(item, &types.AttributeValueMemberBOOL{Value: b}); err != nil { - return err - } - set.SetDirty(idx, true) - return nil - }); err != nil { - return err - } - set.RefreshColumns() - return nil - }); err != nil { - return events.Error(err) - } - return ResultSetUpdated{} - } - }, - } - } -} - -func (twc *TableWriteController) setNullValue(idx int, attr attrPath) tea.Cmd { - return func() tea.Msg { - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { - if err := attr.setAt(item, &types.AttributeValueMemberNULL{Value: true}); err != nil { + set.SetDirty(idx, true) + return nil + }); err != nil { return err } - set.SetDirty(idx, true) + set.RefreshColumns() return nil }); err != nil { - return err + return events.Error(err) } - set.RefreshColumns() - return nil - }); err != nil { - return events.Error(err) - } - return ResultSetUpdated{} + return ResultSetUpdated{} + }, } } -func (twc *TableWriteController) DeleteAttribute(idx int, key string) tea.Cmd { - return func() tea.Msg { - // Verify that the expression is valid - apPath := newAttrPath(key) - - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - _, err := apPath.follow(set.Items()[idx]) - return err - }); err != nil { - return events.Error(err) - } - - if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { - err := apPath.deleteAt(set.Items()[idx]) +func (twc *TableWriteController) setBoolValue(idx int, attr attrPath) tea.Msg { + return events.PromptForInputMsg{ + Prompt: "bool value: ", + OnDone: func(value string) tea.Msg { + b, err := strconv.ParseBool(value) if err != nil { + return events.Error(err) + } + + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { + if err := attr.setAt(item, &types.AttributeValueMemberBOOL{Value: b}); err != nil { + return err + } + set.SetDirty(idx, true) + return nil + }); err != nil { + return err + } + set.RefreshColumns() + return nil + }); err != nil { + return events.Error(err) + } + return ResultSetUpdated{} + }, + } +} + +func (twc *TableWriteController) setNullValue(idx int, attr attrPath) tea.Msg { + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error { + if err := attr.setAt(item, &types.AttributeValueMemberNULL{Value: true}); err != nil { return err } - set.SetDirty(idx, true) - set.RefreshColumns() return nil }); err != nil { - return events.Error(err) + return err + } + set.RefreshColumns() + return nil + }); err != nil { + return events.Error(err) + } + return ResultSetUpdated{} +} + +func (twc *TableWriteController) DeleteAttribute(idx int, key string) tea.Msg { + // Verify that the expression is valid + apPath := newAttrPath(key) + + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + _, err := apPath.follow(set.Items()[idx]) + return err + }); err != nil { + return events.Error(err) + } + + if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error { + err := apPath.deleteAt(set.Items()[idx]) + if err != nil { + return err } - return ResultSetUpdated{} + set.SetDirty(idx, true) + set.RefreshColumns() + return nil + }); err != nil { + return events.Error(err) + } + + return ResultSetUpdated{} +} + +func (twc *TableWriteController) PutItem(idx int) tea.Msg { + resultSet := twc.state.ResultSet() + if !resultSet.IsDirty(idx) { + return events.Error(errors.New("item is not dirty")) + } + + return events.PromptForInputMsg{ + Prompt: "put item? ", + OnDone: func(value string) tea.Msg { + if value != "y" { + return nil + } + + if err := twc.tableService.PutItemAt(context.Background(), resultSet, idx); err != nil { + return events.Error(err) + } + return ResultSetUpdated{} + }, } } -func (twc *TableWriteController) PutItem(idx int) tea.Cmd { - return func() tea.Msg { - resultSet := twc.state.ResultSet() - if !resultSet.IsDirty(idx) { - return events.Error(errors.New("item is not dirty")) - } +func (twc *TableWriteController) PutItems() tea.Msg { + var ( + markedItemCount int + ) + var itemsToPut []models.ItemIndex - return events.PromptForInputMsg{ - Prompt: "put item? ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - if value != "y" { - return nil - } - - if err := twc.tableService.PutItemAt(context.Background(), resultSet, idx); err != nil { - return events.Error(err) - } - return ResultSetUpdated{} - } - }, - } - } -} - -func (twc *TableWriteController) PutItems() tea.Cmd { - return func() tea.Msg { - var ( - markedItemCount int - ) - var itemsToPut []models.ItemIndex - - twc.state.withResultSet(func(rs *models.ResultSet) { - if markedItems := rs.MarkedItems(); len(markedItems) > 0 { - for _, mi := range markedItems { - markedItemCount += 1 - if rs.IsDirty(mi.Index) { - itemsToPut = append(itemsToPut, mi) - } - } - } else { - for i, itm := range rs.Items() { - if rs.IsDirty(i) { - itemsToPut = append(itemsToPut, models.ItemIndex{Item: itm, Index: i}) - } + twc.state.withResultSet(func(rs *models.ResultSet) { + if markedItems := rs.MarkedItems(); len(markedItems) > 0 { + for _, mi := range markedItems { + markedItemCount += 1 + if rs.IsDirty(mi.Index) { + itemsToPut = append(itemsToPut, mi) } } - }) - - if len(itemsToPut) == 0 { - if markedItemCount > 0 { - return events.StatusMsg("no marked items are modified") - } else { - return events.StatusMsg("no items are modified") - } - } - - var promptMessage string - if markedItemCount > 0 { - promptMessage = applyToN("put ", len(itemsToPut), "marked item", "marked items", "? ") } else { - promptMessage = applyToN("put ", len(itemsToPut), "item", "items", "? ") - } - - return events.PromptForInputMsg{ - Prompt: promptMessage, - OnDone: func(value string) tea.Cmd { - if value != "y" { - return events.SetStatus("operation aborted") + for i, itm := range rs.Items() { + if rs.IsDirty(i) { + itemsToPut = append(itemsToPut, models.ItemIndex{Item: itm, Index: i}) } - - return func() tea.Msg { - if err := twc.state.withResultSetReturningError(func(rs *models.ResultSet) error { - err := twc.tableService.PutSelectedItems(context.Background(), rs, itemsToPut) - if err != nil { - return err - } - return nil - }); err != nil { - return events.Error(err) - } - - return ResultSetUpdated{ - statusMessage: applyToN("", len(itemsToPut), "item", "item", " put to table"), - } - } - }, + } } + }) + + if len(itemsToPut) == 0 { + if markedItemCount > 0 { + return events.StatusMsg("no marked items are modified") + } else { + return events.StatusMsg("no items are modified") + } + } + + var promptMessage string + if markedItemCount > 0 { + promptMessage = applyToN("put ", len(itemsToPut), "marked item", "marked items", "? ") + } else { + promptMessage = applyToN("put ", len(itemsToPut), "item", "items", "? ") + } + + return events.PromptForInputMsg{ + Prompt: promptMessage, + OnDone: func(value string) tea.Msg { + if value != "y" { + return events.SetStatus("operation aborted") + } + + if err := twc.state.withResultSetReturningError(func(rs *models.ResultSet) error { + err := twc.tableService.PutSelectedItems(context.Background(), rs, itemsToPut) + if err != nil { + return err + } + return nil + }); err != nil { + return events.Error(err) + } + + return ResultSetUpdated{ + statusMessage: applyToN("", len(itemsToPut), "item", "item", " put to table"), + } + }, } } -func (twc *TableWriteController) TouchItem(idx int) tea.Cmd { - return func() tea.Msg { - resultSet := twc.state.ResultSet() - if resultSet.IsDirty(idx) { - return events.Error(errors.New("cannot touch dirty items")) - } +func (twc *TableWriteController) TouchItem(idx int) tea.Msg { + resultSet := twc.state.ResultSet() + if resultSet.IsDirty(idx) { + return events.Error(errors.New("cannot touch dirty items")) + } - return events.PromptForInputMsg{ - Prompt: "touch item? ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - if value != "y" { - return nil - } + return events.PromptForInputMsg{ + Prompt: "touch item? ", + OnDone: func(value string) tea.Msg { + if value != "y" { + return nil + } - if err := twc.tableService.PutItemAt(context.Background(), resultSet, idx); err != nil { - return events.Error(err) - } - return ResultSetUpdated{} - } - }, - } + if err := twc.tableService.PutItemAt(context.Background(), resultSet, idx); err != nil { + return events.Error(err) + } + return ResultSetUpdated{} + }, } } -func (twc *TableWriteController) NoisyTouchItem(idx int) tea.Cmd { - return func() tea.Msg { - resultSet := twc.state.ResultSet() - if resultSet.IsDirty(idx) { - return events.Error(errors.New("cannot noisy touch dirty items")) - } +func (twc *TableWriteController) NoisyTouchItem(idx int) tea.Msg { + resultSet := twc.state.ResultSet() + if resultSet.IsDirty(idx) { + return events.Error(errors.New("cannot noisy touch dirty items")) + } - return events.PromptForInputMsg{ - Prompt: "noisy touch item? ", - OnDone: func(value string) tea.Cmd { - return func() tea.Msg { - ctx := context.Background() + return events.PromptForInputMsg{ + Prompt: "noisy touch item? ", + OnDone: func(value string) tea.Msg { + ctx := context.Background() - if value != "y" { - return nil - } + if value != "y" { + return nil + } - item := resultSet.Items()[0] - if err := twc.tableService.Delete(ctx, resultSet.TableInfo, []models.Item{item}); err != nil { - return events.Error(err) - } + item := resultSet.Items()[0] + if err := twc.tableService.Delete(ctx, resultSet.TableInfo, []models.Item{item}); err != nil { + return events.Error(err) + } - if err := twc.tableService.Put(ctx, resultSet.TableInfo, item); err != nil { - return events.Error(err) - } + if err := twc.tableService.Put(ctx, resultSet.TableInfo, item); err != nil { + return events.Error(err) + } - return twc.tableReadControllers.doScan(ctx, resultSet, resultSet.Query, false) - } - }, - } + return twc.tableReadControllers.doScan(ctx, resultSet, resultSet.Query, false) + }, } } -func (twc *TableWriteController) DeleteMarked() tea.Cmd { - return func() tea.Msg { - resultSet := twc.state.ResultSet() - markedItems := resultSet.MarkedItems() +func (twc *TableWriteController) DeleteMarked() tea.Msg { + resultSet := twc.state.ResultSet() + markedItems := resultSet.MarkedItems() - if len(markedItems) == 0 { - return events.StatusMsg("no marked items") - } + if len(markedItems) == 0 { + return events.StatusMsg("no marked items") + } - return events.PromptForInputMsg{ - Prompt: applyToN("delete ", len(markedItems), "item", "items", "? "), - OnDone: func(value string) tea.Cmd { - if value != "y" { - return events.SetStatus("operation aborted") - } + return events.PromptForInputMsg{ + Prompt: applyToN("delete ", len(markedItems), "item", "items", "? "), + OnDone: func(value string) tea.Msg { + if value != "y" { + return events.SetStatus("operation aborted") + } - return func() tea.Msg { - ctx := context.Background() - if err := twc.tableService.Delete(ctx, resultSet.TableInfo, sliceutils.Map(markedItems, func(index models.ItemIndex) models.Item { - return index.Item - })); err != nil { - return events.Error(err) - } + ctx := context.Background() + if err := twc.tableService.Delete(ctx, resultSet.TableInfo, sliceutils.Map(markedItems, func(index models.ItemIndex) models.Item { + return index.Item + })); err != nil { + return events.Error(err) + } - return twc.tableReadControllers.doScan(ctx, resultSet, resultSet.Query, false) - } - }, - } + return twc.tableReadControllers.doScan(ctx, resultSet, resultSet.Query, false) + }, } } diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index eaefd2f..3cf2918 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -46,27 +46,27 @@ func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteCon cc.AddCommands(&commandctrl.CommandContext{ Commands: map[string]commandctrl.Command{ "quit": commandctrl.NoArgCommand(tea.Quit), - "table": func(args []string) tea.Cmd { + "table": func(args []string) tea.Msg { if len(args) == 0 { return rc.ListTables() } else { return rc.ScanTable(args[0]) } }, - "export": func(args []string) tea.Cmd { + "export": func(args []string) tea.Msg { if len(args) == 0 { - return events.SetError(errors.New("expected filename")) + return events.Error(errors.New("expected filename")) } return rc.ExportCSV(args[0]) }, - "unmark": commandctrl.NoArgCommand(rc.Unmark()), - "delete": commandctrl.NoArgCommand(wc.DeleteMarked()), + "unmark": commandctrl.NoArgCommand(rc.Unmark), + "delete": commandctrl.NoArgCommand(wc.DeleteMarked), // TEMP - "new-item": commandctrl.NoArgCommand(wc.NewItem()), - "set-attr": func(args []string) tea.Cmd { + "new-item": commandctrl.NoArgCommand(wc.NewItem), + "set-attr": func(args []string) tea.Msg { if len(args) == 0 { - return events.SetError(errors.New("expected field")) + return events.Error(errors.New("expected field")) } var itemType = models.UnsetItemType @@ -81,27 +81,27 @@ func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteCon case "-NULL": itemType = models.NullItemType default: - return events.SetError(errors.New("unrecognised item type")) + return events.Error(errors.New("unrecognised item type")) } args = args[1:] } return wc.SetAttributeValue(dtv.SelectedItemIndex(), itemType, args[0]) }, - "del-attr": func(args []string) tea.Cmd { + "del-attr": func(args []string) tea.Msg { if len(args) == 0 { - return events.SetError(errors.New("expected field")) + return events.Error(errors.New("expected field")) } return wc.DeleteAttribute(dtv.SelectedItemIndex(), args[0]) }, - "put": func(args []string) tea.Cmd { + "put": func(args []string) tea.Msg { return wc.PutItems() }, - "touch": func(args []string) tea.Cmd { + "touch": func(args []string) tea.Msg { return wc.TouchItem(dtv.SelectedItemIndex()) }, - "noisy-touch": func(args []string) tea.Cmd { + "noisy-touch": func(args []string) tea.Msg { return wc.NoisyTouchItem(dtv.SelectedItemIndex()) }, @@ -129,7 +129,7 @@ func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteCon } func (m Model) Init() tea.Cmd { - return m.tableReadController.Init() + return m.tableReadController.Init } func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -141,21 +141,21 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { case "m": if idx := m.tableView.SelectedItemIndex(); idx >= 0 { - return m, m.tableWriteController.ToggleMark(idx) + return m, func() tea.Msg { return m.tableWriteController.ToggleMark(idx) } } case "R": - return m, m.tableReadController.Rescan() + return m, m.tableReadController.Rescan case "?": - return m, m.tableReadController.PromptForQuery() + return m, m.tableReadController.PromptForQuery case "/": - return m, m.tableReadController.Filter() + return m, m.tableReadController.Filter case "backspace": - return m, m.tableReadController.ViewBack() + return m, m.tableReadController.ViewBack //case "e": // m.itemEdit.Visible() // return m, nil case ":": - return m, m.commandController.Prompt() + return m, m.commandController.Prompt case "ctrl+c", "esc": return m, tea.Quit } diff --git a/internal/dynamo-browse/ui/teamodels/statusandprompt/model.go b/internal/dynamo-browse/ui/teamodels/statusandprompt/model.go index 995f0e5..a48dd4f 100644 --- a/internal/dynamo-browse/ui/teamodels/statusandprompt/model.go +++ b/internal/dynamo-browse/ui/teamodels/statusandprompt/model.go @@ -67,7 +67,7 @@ func (s *StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) { pendingInput := s.pendingInput s.pendingInput = nil - return s, pendingInput.OnDone(s.textInput.Value()) + return s, func() tea.Msg { return pendingInput.OnDone(s.textInput.Value()) } default: if msg.Type == tea.KeyRunes { msg.Runes = sliceutils.Filter(msg.Runes, func(r rune) bool { return r != '\x0d' && r != '\x0a' }) diff --git a/internal/dynamo-browse/ui/teamodels/tableselect/model.go b/internal/dynamo-browse/ui/teamodels/tableselect/model.go index b7332ef..18c679b 100644 --- a/internal/dynamo-browse/ui/teamodels/tableselect/model.go +++ b/internal/dynamo-browse/ui/teamodels/tableselect/model.go @@ -55,7 +55,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var sel controllers.PromptForTableMsg sel, m.pendingSelection = *m.pendingSelection, nil - return m, sel.OnSelected(m.listController.list.SelectedItem().(tableItem).name) + return m, func() tea.Msg { return sel.OnSelected(m.listController.list.SelectedItem().(tableItem).name) } } } diff --git a/internal/slog-view/ui/model.go b/internal/slog-view/ui/model.go index a67de34..e153bbd 100644 --- a/internal/slog-view/ui/model.go +++ b/internal/slog-view/ui/model.go @@ -62,7 +62,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { // TEMP case ":": - return m, m.cmdController.Prompt() + return m, func() tea.Msg { return m.cmdController.Prompt() } case "w": return m, m.controller.ViewLogLineFullScreen(m.logLines.SelectedLogLine()) // END TEMP diff --git a/internal/ssm-browse/controllers/ssmcontroller.go b/internal/ssm-browse/controllers/ssmcontroller.go index 2078b78..c54f316 100644 --- a/internal/ssm-browse/controllers/ssmcontroller.go +++ b/internal/ssm-browse/controllers/ssmcontroller.go @@ -39,26 +39,24 @@ func (c *SSMController) Fetch() tea.Cmd { } } -func (c *SSMController) ChangePrefix(newPrefix string) tea.Cmd { - return func() tea.Msg { - res, err := c.service.List(context.Background(), newPrefix) - if err != nil { - return events.Error(err) - } +func (c *SSMController) ChangePrefix(newPrefix string) tea.Msg { + res, err := c.service.List(context.Background(), newPrefix) + if err != nil { + return events.Error(err) + } - c.mutex.Lock() - defer c.mutex.Unlock() - c.prefix = newPrefix + c.mutex.Lock() + defer c.mutex.Unlock() + c.prefix = newPrefix - return NewParameterListMsg{ - Prefix: c.prefix, - Parameters: res, - } + return NewParameterListMsg{ + Prefix: c.prefix, + Parameters: res, } } -func (c *SSMController) Clone(param models.SSMParameter) tea.Cmd { - return events.PromptForInput("New key: ", func(value string) tea.Cmd { +func (c *SSMController) Clone(param models.SSMParameter) tea.Msg { + return events.PromptForInput("New key: ", func(value string) tea.Msg { return func() tea.Msg { ctx := context.Background() if err := c.service.Clone(ctx, param, value); err != nil { @@ -78,23 +76,21 @@ func (c *SSMController) Clone(param models.SSMParameter) tea.Cmd { }) } -func (c *SSMController) DeleteParameter(param models.SSMParameter) tea.Cmd { - return events.Confirm("delete parameter? ", func() tea.Cmd { - return func() tea.Msg { - ctx := context.Background() - if err := c.service.Delete(ctx, param); err != nil { - return events.Error(err) - } +func (c *SSMController) DeleteParameter(param models.SSMParameter) tea.Msg { + return events.Confirm("delete parameter? ", func() tea.Msg { + ctx := context.Background() + if err := c.service.Delete(ctx, param); err != nil { + return events.Error(err) + } - res, err := c.service.List(context.Background(), c.prefix) - if err != nil { - return events.Error(err) - } + res, err := c.service.List(context.Background(), c.prefix) + if err != nil { + return events.Error(err) + } - return NewParameterListMsg{ - Prefix: c.prefix, - Parameters: res, - } + return NewParameterListMsg{ + Prefix: c.prefix, + Parameters: res, } }) } diff --git a/internal/ssm-browse/ui/model.go b/internal/ssm-browse/ui/model.go index a0fceae..985b694 100644 --- a/internal/ssm-browse/ui/model.go +++ b/internal/ssm-browse/ui/model.go @@ -32,17 +32,17 @@ func NewModel(controller *controllers.SSMController, cmdController *commandctrl. cmdController.AddCommands(&commandctrl.CommandContext{ Commands: map[string]commandctrl.Command{ - "clone": func(args []string) tea.Cmd { + "clone": func(args []string) tea.Msg { if currentParam := ssmList.CurrentParameter(); currentParam != nil { return controller.Clone(*currentParam) } - return events.SetError(errors.New("no parameter selected")) + return events.Error(errors.New("no parameter selected")) }, - "delete": func(args []string) tea.Cmd { + "delete": func(args []string) tea.Msg { if currentParam := ssmList.CurrentParameter(); currentParam != nil { return controller.DeleteParameter(*currentParam) } - return events.SetError(errors.New("no parameter selected")) + return events.Error(errors.New("no parameter selected")) }, }, }) @@ -75,7 +75,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { // TEMP case ":": - return m, m.cmdController.Prompt() + return m, func() tea.Msg { return m.cmdController.Prompt() } // END TEMP case "ctrl+c", "q":