keys.go

  1package models
  2
  3import (
  4	"charm.land/bubbles/v2/key"
  5)
  6
  7type KeyMap struct {
  8	Select,
  9	Next,
 10	Previous,
 11	Choose,
 12	Tab,
 13	Close key.Binding
 14
 15	isAPIKeyHelp  bool
 16	isAPIKeyValid bool
 17
 18	isHyperDeviceFlow    bool
 19	isCopilotDeviceFlow  bool
 20	isCopilotUnavailable bool
 21
 22	isClaudeAuthChoiceHelp    bool
 23	isClaudeOAuthHelp         bool
 24	isClaudeOAuthURLState     bool
 25	isClaudeOAuthHelpComplete bool
 26}
 27
 28func DefaultKeyMap() KeyMap {
 29	return KeyMap{
 30		Select: key.NewBinding(
 31			key.WithKeys("enter", "ctrl+y"),
 32			key.WithHelp("enter", "choose"),
 33		),
 34		Next: key.NewBinding(
 35			key.WithKeys("down", "ctrl+n"),
 36			key.WithHelp("↓", "next item"),
 37		),
 38		Previous: key.NewBinding(
 39			key.WithKeys("up", "ctrl+p"),
 40			key.WithHelp("↑", "previous item"),
 41		),
 42		Choose: key.NewBinding(
 43			key.WithKeys("left", "right", "h", "l"),
 44			key.WithHelp("←→", "choose"),
 45		),
 46		Tab: key.NewBinding(
 47			key.WithKeys("tab"),
 48			key.WithHelp("tab", "toggle type"),
 49		),
 50		Close: key.NewBinding(
 51			key.WithKeys("esc", "alt+esc"),
 52			key.WithHelp("esc", "exit"),
 53		),
 54	}
 55}
 56
 57// KeyBindings implements layout.KeyMapProvider
 58func (k KeyMap) KeyBindings() []key.Binding {
 59	return []key.Binding{
 60		k.Select,
 61		k.Next,
 62		k.Previous,
 63		k.Tab,
 64		k.Close,
 65	}
 66}
 67
 68// FullHelp implements help.KeyMap.
 69func (k KeyMap) FullHelp() [][]key.Binding {
 70	m := [][]key.Binding{}
 71	slice := k.KeyBindings()
 72	for i := 0; i < len(slice); i += 4 {
 73		end := min(i+4, len(slice))
 74		m = append(m, slice[i:end])
 75	}
 76	return m
 77}
 78
 79// ShortHelp implements help.KeyMap.
 80func (k KeyMap) ShortHelp() []key.Binding {
 81	if k.isHyperDeviceFlow || k.isCopilotDeviceFlow {
 82		return []key.Binding{
 83			key.NewBinding(
 84				key.WithKeys("c"),
 85				key.WithHelp("c", "copy code"),
 86			),
 87			key.NewBinding(
 88				key.WithKeys("enter"),
 89				key.WithHelp("enter", "copy & open"),
 90			),
 91			k.Close,
 92		}
 93	}
 94	if k.isCopilotUnavailable {
 95		return []key.Binding{
 96			key.NewBinding(
 97				key.WithKeys("enter"),
 98				key.WithHelp("enter", "open signup"),
 99			),
100			k.Close,
101		}
102	}
103	if k.isClaudeAuthChoiceHelp {
104		return []key.Binding{
105			key.NewBinding(
106				key.WithKeys("left", "right", "h", "l"),
107				key.WithHelp("←→", "choose"),
108			),
109			key.NewBinding(
110				key.WithKeys("enter"),
111				key.WithHelp("enter", "accept"),
112			),
113			key.NewBinding(
114				key.WithKeys("esc"),
115				key.WithHelp("esc", "back"),
116			),
117		}
118	}
119	if k.isClaudeOAuthHelp {
120		if k.isClaudeOAuthHelpComplete {
121			return []key.Binding{
122				key.NewBinding(
123					key.WithKeys("enter"),
124					key.WithHelp("enter", "close"),
125				),
126			}
127		}
128
129		enterHelp := "submit"
130		if k.isClaudeOAuthURLState {
131			enterHelp = "open"
132		}
133
134		bindings := []key.Binding{
135			key.NewBinding(
136				key.WithKeys("enter"),
137				key.WithHelp("enter", enterHelp),
138			),
139		}
140
141		if k.isClaudeOAuthURLState {
142			bindings = append(bindings, key.NewBinding(
143				key.WithKeys("c"),
144				key.WithHelp("c", "copy url"),
145			))
146		}
147
148		bindings = append(bindings, key.NewBinding(
149			key.WithKeys("esc"),
150			key.WithHelp("esc", "back"),
151		))
152
153		return bindings
154	}
155	if k.isAPIKeyHelp && !k.isAPIKeyValid {
156		return []key.Binding{
157			key.NewBinding(
158				key.WithKeys("enter"),
159				key.WithHelp("enter", "submit"),
160			),
161			k.Close,
162		}
163	} else if k.isAPIKeyValid {
164		return []key.Binding{
165			k.Select,
166		}
167	}
168	return []key.Binding{
169		key.NewBinding(
170			key.WithKeys("down", "up"),
171			key.WithHelp("↑↓", "choose"),
172		),
173		k.Tab,
174		k.Select,
175		k.Close,
176	}
177}