issue-9: finishing keybinding service and implemented controller
Have now got rebinding keys working with the "rebind" command. Still need to make sure key names are correct and implement rebinding as part of an RC file and add bindings for the table.
This commit is contained in:
parent
2f89610c51
commit
7c5bfd27a3
6 changed files with 159 additions and 17 deletions
14
internal/dynamo-browse/services/keybindings/errors.go
Normal file
14
internal/dynamo-browse/services/keybindings/errors.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package keybindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type KeyAlreadyBoundError struct {
|
||||
Key string
|
||||
ExistingBindingName string
|
||||
}
|
||||
|
||||
func (e KeyAlreadyBoundError) Error() string {
|
||||
return fmt.Sprintf("key '%v' already bound to '%v'", e.Key, e.ExistingBindingName)
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
package keybindings
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/pkg/errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
keyBindingValue reflect.Value
|
||||
|
|
@ -17,16 +22,95 @@ func NewService(keyBinding any) *Service {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Service) Rebind(name string, key string) error {
|
||||
func (s *Service) Rebind(newKey string, name string, force bool) error {
|
||||
// Check if there already exists a binding
|
||||
if !force {
|
||||
var foundBinding = ""
|
||||
s.walkBindingFields(func(bindingName string, binding key.Binding) bool {
|
||||
for _, key := range binding.Keys() {
|
||||
if key == newKey {
|
||||
foundBinding = bindingName
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
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().
|
||||
if foundBinding != "" {
|
||||
return KeyAlreadyBoundError{Key: newKey, ExistingBindingName: foundBinding}
|
||||
}
|
||||
}
|
||||
|
||||
// Rebind
|
||||
binding := s.findFieldForBinding(name)
|
||||
if binding == nil {
|
||||
return errors.Errorf("invalid binding: %v", name)
|
||||
}
|
||||
|
||||
*binding = key.NewBinding(key.WithKeys(newKey))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) findFieldForBinding(name string) *key.Binding {
|
||||
return s.findFieldForBindingInGroup(s.keyBindingValue, name)
|
||||
}
|
||||
|
||||
func (s *Service) findFieldForBindingInGroup(group reflect.Value, name string) *key.Binding {
|
||||
bindingName, bindingSuffix, _ := strings.Cut(name, ".")
|
||||
|
||||
groupType := group.Type()
|
||||
for i := 0; i < group.NumField(); i++ {
|
||||
fieldType := groupType.Field(i)
|
||||
|
||||
keymapTag := fieldType.Tag.Get("keymap")
|
||||
if keymapTag != bindingName {
|
||||
continue
|
||||
}
|
||||
|
||||
if fieldType.Type.Kind() == reflect.Pointer && fieldType.Type.Elem().Kind() == reflect.Struct {
|
||||
return s.findFieldForBindingInGroup(group.Field(i).Elem(), bindingSuffix)
|
||||
}
|
||||
|
||||
binding, isBinding := group.Field(i).Addr().Interface().(*key.Binding)
|
||||
if !isBinding {
|
||||
return nil
|
||||
}
|
||||
return binding
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) walkBindingFields(fn func(name string, binding key.Binding) bool) {
|
||||
s.walkBindingFieldsInGroup(s.keyBindingValue, "", fn)
|
||||
}
|
||||
|
||||
func (s *Service) walkBindingFieldsInGroup(group reflect.Value, prefix string, fn func(name string, binding key.Binding) bool) bool {
|
||||
groupType := group.Type()
|
||||
for i := 0; i < group.NumField(); i++ {
|
||||
fieldType := groupType.Field(i)
|
||||
|
||||
keymapTag := fieldType.Tag.Get("keymap")
|
||||
|
||||
var fullName string
|
||||
if prefix != "" {
|
||||
fullName = prefix + "." + keymapTag
|
||||
} else {
|
||||
fullName = keymapTag
|
||||
}
|
||||
|
||||
if fieldType.Type.Kind() == reflect.Pointer && fieldType.Type.Elem().Kind() == reflect.Struct {
|
||||
if !s.walkBindingFieldsInGroup(group.Field(i).Elem(), fullName, fn) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
binding, isBinding := group.Field(i).Addr().Interface().(*key.Binding)
|
||||
if !isBinding {
|
||||
continue
|
||||
}
|
||||
if !fn(fullName, *binding) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue