key.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Package key provides some types and functions for generating user-definable
  2. // keymappings useful in Bubble Tea components. There are a few different ways
  3. // you can define a keymapping with this package. Here's one example:
  4. //
  5. // type KeyMap struct {
  6. // Up key.Binding
  7. // Down key.Binding
  8. // }
  9. //
  10. // var DefaultKeyMap = KeyMap{
  11. // Up: key.NewBinding(
  12. // key.WithKeys("k", "up"), // actual keybindings
  13. // key.WithHelp("↑/k", "move up"), // corresponding help text
  14. // ),
  15. // Down: key.NewBinding(
  16. // key.WithKeys("j", "down"),
  17. // key.WithHelp("↓/j", "move down"),
  18. // ),
  19. // }
  20. //
  21. // func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  22. // switch msg := msg.(type) {
  23. // case tea.KeyMsg:
  24. // switch {
  25. // case key.Matches(msg, DefaultKeyMap.Up):
  26. // // The user pressed up
  27. // case key.Matches(msg, DefaultKeyMap.Down):
  28. // // The user pressed down
  29. // }
  30. // }
  31. //
  32. // // ...
  33. // }
  34. //
  35. // The help information, which is not used in the example above, can be used
  36. // to render help text for keystrokes in your views.
  37. package key
  38. import (
  39. tea "github.com/charmbracelet/bubbletea"
  40. )
  41. // Binding describes a set of keybindings and, optionally, their associated
  42. // help text.
  43. type Binding struct {
  44. keys []string
  45. help Help
  46. disabled bool
  47. }
  48. // BindingOpt is an initialization option for a keybinding. It's used as an
  49. // argument to NewBinding.
  50. type BindingOpt func(*Binding)
  51. // NewBinding returns a new keybinding from a set of BindingOpt options.
  52. func NewBinding(opts ...BindingOpt) Binding {
  53. b := &Binding{}
  54. for _, opt := range opts {
  55. opt(b)
  56. }
  57. return *b
  58. }
  59. // WithKeys initializes a keybinding with the given keystrokes.
  60. func WithKeys(keys ...string) BindingOpt {
  61. return func(b *Binding) {
  62. b.keys = keys
  63. }
  64. }
  65. // WithHelp initializes a keybinding with the given help text.
  66. func WithHelp(key, desc string) BindingOpt {
  67. return func(b *Binding) {
  68. b.help = Help{Key: key, Desc: desc}
  69. }
  70. }
  71. // WithDisabled initializes a disabled keybinding.
  72. func WithDisabled() BindingOpt {
  73. return func(b *Binding) {
  74. b.disabled = true
  75. }
  76. }
  77. // SetKeys sets the keys for the keybinding.
  78. func (b *Binding) SetKeys(keys ...string) {
  79. b.keys = keys
  80. }
  81. // Keys returns the keys for the keybinding.
  82. func (b Binding) Keys() []string {
  83. return b.keys
  84. }
  85. // SetHelp sets the help text for the keybinding.
  86. func (b *Binding) SetHelp(key, desc string) {
  87. b.help = Help{Key: key, Desc: desc}
  88. }
  89. // Help returns the Help information for the keybinding.
  90. func (b Binding) Help() Help {
  91. return b.help
  92. }
  93. // Enabled returns whether or not the keybinding is enabled. Disabled
  94. // keybindings won't be activated and won't show up in help. Keybindings are
  95. // enabled by default.
  96. func (b Binding) Enabled() bool {
  97. return !b.disabled && b.keys != nil
  98. }
  99. // SetEnabled enables or disables the keybinding.
  100. func (b *Binding) SetEnabled(v bool) {
  101. b.disabled = !v
  102. }
  103. // Unbind removes the keys and help from this binding, effectively nullifying
  104. // it. This is a step beyond disabling it, since applications can enable
  105. // or disable key bindings based on application state.
  106. func (b *Binding) Unbind() {
  107. b.keys = nil
  108. b.help = Help{}
  109. }
  110. // Help is help information for a given keybinding.
  111. type Help struct {
  112. Key string
  113. Desc string
  114. }
  115. // Matches checks if the given KeyMsg matches the given bindings.
  116. func Matches(k tea.KeyMsg, b ...Binding) bool {
  117. keys := k.String()
  118. for _, binding := range b {
  119. for _, v := range binding.keys {
  120. if keys == v && binding.Enabled() {
  121. return true
  122. }
  123. }
  124. }
  125. return false
  126. }