From 2f89610c51ac4e08b40cdbc450e9a7c22fb6350a Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Wed, 24 Aug 2022 22:06:29 +1000 Subject: [PATCH] issue-9: moved keybindings out into a separate type Also started working on a service which can be used to rebind keys using reflection. --- cmd/dynamo-browse/main.go | 29 +++++++++++++++- internal/dynamo-browse/controllers/events.go | 2 +- .../services/keybindings/service.go | 32 ++++++++++++++++++ internal/dynamo-browse/ui/keybindings.go | 21 ++++++++++++ internal/dynamo-browse/ui/model.go | 33 +++++++++++-------- 5 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 internal/dynamo-browse/services/keybindings/service.go create mode 100644 internal/dynamo-browse/ui/keybindings.go diff --git a/cmd/dynamo-browse/main.go b/cmd/dynamo-browse/main.go index cafbe4f..76257cb 100644 --- a/cmd/dynamo-browse/main.go +++ b/cmd/dynamo-browse/main.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/lmika/audax/internal/common/ui/commandctrl" @@ -16,6 +17,7 @@ import ( "github.com/lmika/audax/internal/dynamo-browse/providers/dynamo" "github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore" "github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer" + "github.com/lmika/audax/internal/dynamo-browse/services/keybindings" "github.com/lmika/audax/internal/dynamo-browse/services/tables" workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces" "github.com/lmika/audax/internal/dynamo-browse/ui" @@ -80,8 +82,33 @@ func main() { tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, itemRendererService, *flagTable, true) tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController) + defaultKeyBindings := &ui.KeyBindings{ + View: &ui.ViewKeyBindings{ + Mark: key.NewBinding(key.WithKeys("m"), key.WithHelp("m", "mark")), + CopyItemToClipboard: key.NewBinding(key.WithKeys("c"), key.WithHelp("c", "copy item to clipboard")), + Rescan: key.NewBinding(key.WithKeys("R"), key.WithHelp("R", "rescan")), + PromptForQuery: key.NewBinding(key.WithKeys("?"), key.WithHelp("?", "prompt for query")), + PromptForFilter: key.NewBinding(key.WithKeys("f"), key.WithHelp("/", "filter")), + ViewBack: key.NewBinding(key.WithKeys("backspace"), key.WithHelp("backspace", "go back")), + ViewForward: key.NewBinding(key.WithKeys("\\"), key.WithHelp("\\", "go forward")), + CycleLayoutForward: key.NewBinding(key.WithKeys("w"), key.WithHelp("w", "cycle layout forward")), + CycleLayoutBackwards: key.NewBinding(key.WithKeys("W"), key.WithHelp("W", "cycle layout backward")), + PromptForCommand: key.NewBinding(key.WithKeys(":"), key.WithHelp(":", "prompt for command")), + Quit: key.NewBinding(key.WithKeys("ctrl+c", "esc"), key.WithHelp("ctrl+c/esc", "quit")), + }, + } + commandController := commandctrl.NewCommandController() - model := ui.NewModel(tableReadController, tableWriteController, itemRendererService, commandController) + keyBindingService := keybindings.NewService(defaultKeyBindings) + _ = keyBindingService + + model := ui.NewModel( + tableReadController, + tableWriteController, + itemRendererService, + commandController, + defaultKeyBindings, + ) // Pre-determine if layout has dark background. This prevents calls for creating a list to hang. lipgloss.HasDarkBackground() diff --git a/internal/dynamo-browse/controllers/events.go b/internal/dynamo-browse/controllers/events.go index 9e1bbae..7896902 100644 --- a/internal/dynamo-browse/controllers/events.go +++ b/internal/dynamo-browse/controllers/events.go @@ -27,7 +27,7 @@ func (rs NewResultSet) ModeMessage() string { } if rs.currentFilter != "" { - modeLine = fmt.Sprintf("%v - Filter: '%v'", modeLine, rs.currentFilter) + modeLine = fmt.Sprintf("%v - PromptForFilter: '%v'", modeLine, rs.currentFilter) } return modeLine } diff --git a/internal/dynamo-browse/services/keybindings/service.go b/internal/dynamo-browse/services/keybindings/service.go new file mode 100644 index 0000000..7535f49 --- /dev/null +++ b/internal/dynamo-browse/services/keybindings/service.go @@ -0,0 +1,32 @@ +package keybindings + +import "reflect" + +type Service struct { + keyBindingValue reflect.Value +} + +func NewService(keyBinding any) *Service { + v := reflect.ValueOf(keyBinding) + if v.Kind() != reflect.Pointer { + panic("keyBinding must be a pointer to a struct") + } + + return &Service{ + keyBindingValue: v.Elem(), + } +} + +func (s *Service) Rebind(name string, key string) error { + +} + +func (s *Service) findFieldForBinding(name string) reflect.Value { + +} + +func (s *Service) findFieldForBindingInGroup(group reflect.Value, name string) reflect.Value { + for i := 0; i < group.NumField(); i++ { + group.Field(i).Type(). + } +} diff --git a/internal/dynamo-browse/ui/keybindings.go b/internal/dynamo-browse/ui/keybindings.go new file mode 100644 index 0000000..b56d454 --- /dev/null +++ b/internal/dynamo-browse/ui/keybindings.go @@ -0,0 +1,21 @@ +package ui + +import "github.com/charmbracelet/bubbles/key" + +type KeyBindings struct { + View *ViewKeyBindings `keymap:"view,group"` +} + +type ViewKeyBindings struct { + Mark key.Binding `keymap:"mark"` + CopyItemToClipboard key.Binding `keymap:"copy-item-to-clipboard"` + Rescan key.Binding `keymap:"rescan"` + PromptForQuery key.Binding `keymap:"prompt-for-query"` + PromptForFilter key.Binding `keymap:"prompt-for-filter"` + ViewBack key.Binding `keymap:"view-back"` + ViewForward key.Binding `keymap:"view-forward"` + CycleLayoutForward key.Binding `keymap:"cycle-layout-forward"` + CycleLayoutBackwards key.Binding `keymap:"cycle-layout-backwards"` + PromptForCommand key.Binding `keymap:"prompt-for-command"` + Quit key.Binding `keymap:"quit"` +} diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index c5584c3..c1c4177 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -1,6 +1,7 @@ package ui import ( + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/lmika/audax/internal/common/ui/commandctrl" "github.com/lmika/audax/internal/common/ui/events" @@ -45,6 +46,7 @@ type Model struct { tableView *dynamotableview.Model itemView *dynamoitemview.Model mainView tea.Model + keyMap *ViewKeyBindings } func NewModel( @@ -52,6 +54,7 @@ func NewModel( wc *controllers.TableWriteController, itemRendererService *itemrenderer.Service, cc *commandctrl.CommandController, + defaultKeyMap *KeyBindings, ) Model { uiStyles := styles.DefaultStyles @@ -126,6 +129,10 @@ func NewModel( return wc.NoisyTouchItem(dtv.SelectedItemIndex()) }, + //"rebind": func(args []string) tea.Msg { + // + //}, + // Aliases "sa": cc.Alias("set-attr"), "da": cc.Alias("del-attr"), @@ -147,6 +154,7 @@ func NewModel( tableView: dtv, itemView: div, mainView: mainView, + keyMap: defaultKeyMap.View, } } @@ -163,40 +171,39 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, m.tableView.Refresh() case tea.KeyMsg: if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() { - log.Printf("key = %+v", msg) - switch msg.String() { - case "m": + switch { + case key.Matches(msg, m.keyMap.Mark): if idx := m.tableView.SelectedItemIndex(); idx >= 0 { return m, func() tea.Msg { return m.tableWriteController.ToggleMark(idx) } } - case "c": + case key.Matches(msg, m.keyMap.CopyItemToClipboard): if idx := m.tableView.SelectedItemIndex(); idx >= 0 { return m, func() tea.Msg { return m.tableReadController.CopyItemToClipboard(idx) } } - case "R": + case key.Matches(msg, m.keyMap.Rescan): return m, m.tableReadController.Rescan - case "?": + case key.Matches(msg, m.keyMap.PromptForQuery): return m, m.tableReadController.PromptForQuery - case "/": + case key.Matches(msg, m.keyMap.PromptForFilter): return m, m.tableReadController.Filter - case "backspace": + case key.Matches(msg, m.keyMap.ViewBack): return m, m.tableReadController.ViewBack - case "\\": + case key.Matches(msg, m.keyMap.ViewForward): return m, m.tableReadController.ViewForward - case "w": + case key.Matches(msg, m.keyMap.CycleLayoutForward): return m, func() tea.Msg { return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, 1, ViewModeCount)} } - case "W": + case key.Matches(msg, m.keyMap.CycleLayoutBackwards): return m, func() tea.Msg { return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, -1, ViewModeCount)} } //case "e": // m.itemEdit.Visible() // return m, nil - case ":": + case key.Matches(msg, m.keyMap.PromptForCommand): return m, m.commandController.Prompt - case "ctrl+c", "esc": + case key.Matches(msg, m.keyMap.Quit): return m, tea.Quit } }