6 "github.com/zyedidia/tcell/v2"
9 type PaneKeyAction func(Pane) bool
10 type PaneMouseAction func(Pane, *tcell.EventMouse) bool
11 type PaneKeyAnyAction func(Pane, []KeyEvent) bool
13 // A KeyTreeNode stores a single node in the KeyTree (trie). The
14 // children are stored as a map, and any node may store a list of
15 // actions (the list will be nil if no actions correspond to a certain
17 type KeyTreeNode struct {
18 children map[Event]*KeyTreeNode
20 // Only one of these actions may be active in the current
21 // mode, and only one will be returned. If multiple actions
22 // are active, it is undefined which one will be the one
27 func NewKeyTreeNode() *KeyTreeNode {
29 n.children = make(map[Event]*KeyTreeNode)
30 n.actions = []TreeAction{}
34 // A TreeAction stores an action, and a set of mode constraints for
35 // the action to be active.
36 type TreeAction struct {
37 // only one of these can be non-nil
42 modes []ModeConstraint
45 // A KeyTree is a data structure for storing keybindings. It maps
46 // key events to actions, and maintains a set of currently enabled
47 // modes, which affects the action that is returned for a key event.
48 // The tree acts like a Trie for Events to handle sequence events.
56 // A KeyTreeCursor keeps track of the current location within the
57 // tree, and stores any information from previous events that may
58 // be needed to execute the action (values of wildcard events or
60 type KeyTreeCursor struct {
63 recordedEvents []Event
65 mouseInfo *tcell.EventMouse
68 // MakeClosure uses the information stored in a key tree cursor to construct
69 // a PaneKeyAction from a TreeAction (which may have a PaneKeyAction, PaneMouseAction,
71 func (k *KeyTreeCursor) MakeClosure(a TreeAction) PaneKeyAction {
74 } else if a.any != nil {
75 return func(p Pane) bool {
76 return a.any(p, k.wildcards)
78 } else if a.mouse != nil {
79 return func(p Pane) bool {
80 return a.mouse(p, k.mouseInfo)
87 // NewKeyTree allocates and returns an empty key tree
88 func NewKeyTree() *KeyTree {
89 root := NewKeyTreeNode()
93 tree.modes = make(map[string]bool)
94 tree.cursor = KeyTreeCursor{
96 wildcards: []KeyEvent{},
103 // A ModeConstraint specifies that an action can only be executed
104 // while a certain mode is enabled or disabled.
105 type ModeConstraint struct {
110 // RegisterKeyBinding registers a PaneKeyAction with an Event.
111 func (k *KeyTree) RegisterKeyBinding(e Event, a PaneKeyAction) {
112 k.registerBinding(e, TreeAction{
120 // RegisterKeyAnyBinding registers a PaneKeyAnyAction with an Event.
121 // The event should contain an "any" event.
122 func (k *KeyTree) RegisterKeyAnyBinding(e Event, a PaneKeyAnyAction) {
123 k.registerBinding(e, TreeAction{
131 // RegisterMouseBinding registers a PaneMouseAction with an Event.
132 // The event should contain a mouse event.
133 func (k *KeyTree) RegisterMouseBinding(e Event, a PaneMouseAction) {
134 k.registerBinding(e, TreeAction{
142 func (k *KeyTree) registerBinding(e Event, a TreeAction) {
143 switch ev := e.(type) {
144 case KeyEvent, MouseEvent, RawEvent:
145 newNode, ok := k.root.children[e]
147 newNode = NewKeyTreeNode()
148 k.root.children[e] = newNode
150 // newNode.actions = append(newNode.actions, a)
151 newNode.actions = []TreeAction{a}
152 case KeySequenceEvent:
154 for _, key := range ev.keys {
155 newNode, ok := n.children[key]
157 newNode = NewKeyTreeNode()
158 n.children[key] = newNode
163 // n.actions = append(n.actions, a)
164 n.actions = []TreeAction{a}
168 // NextEvent returns the action for the current sequence where e is the next
169 // event. Even if the action was registered as a PaneKeyAnyAction or PaneMouseAction,
170 // it will be returned as a PaneKeyAction closure where the appropriate arguments
171 // have been provided.
172 // If no action is associated with the given Event, or mode constraints are not
173 // met for that action, nil is returned.
174 // A boolean is returned to indicate if there is a conflict with this action. A
175 // conflict occurs when there is an active action for this event but there are
176 // bindings associated with further sequences starting with this event. The
177 // calling function can decide what to do about the conflict (e.g. use a
179 func (k *KeyTree) NextEvent(e Event, mouse *tcell.EventMouse) (PaneKeyAction, bool) {
181 c, ok := n.children[e]
187 more := len(c.children) > 0
191 k.cursor.recordedEvents = append(k.cursor.recordedEvents, e)
193 switch ev := e.(type) {
196 k.cursor.wildcards = append(k.cursor.wildcards, ev)
199 k.cursor.mouseInfo = mouse
202 if len(c.actions) > 0 {
203 // check if actions are active
204 for _, a := range c.actions {
206 for _, mc := range a.modes {
207 // if any mode constraint is not met, the action is not active
208 hasMode := k.modes[mc.mode]
209 if hasMode != mc.disabled {
215 // the first active action to be found is returned
216 return k.cursor.MakeClosure(a), more
224 // ResetEvents sets the current sequence back to the initial value.
225 func (k *KeyTree) ResetEvents() {
226 k.cursor.node = k.root
227 k.cursor.wildcards = []KeyEvent{}
228 k.cursor.recordedEvents = []Event{}
229 k.cursor.mouseInfo = nil
232 // RecordedEventsStr returns the list of recorded events as a string
233 func (k *KeyTree) RecordedEventsStr() string {
234 buf := &bytes.Buffer{}
235 for _, e := range k.cursor.recordedEvents {
236 buf.WriteString(e.Name())
241 // DeleteBinding removes any currently active actions associated with the
243 func (k *KeyTree) DeleteBinding(e Event) {
247 // DeleteAllBindings removes all actions associated with the given event,
248 // regardless of whether they are active or not.
249 func (k *KeyTree) DeleteAllBindings(e Event) {
253 // SetMode enables or disabled a given mode
254 func (k *KeyTree) SetMode(mode string, en bool) {
258 // HasMode returns if the given mode is currently active
259 func (k *KeyTree) HasMode(mode string) bool {