Something went wrong. Try again.
Fork of micro-editor/micro
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189package action
import ( "bytes" "errors" "fmt" "strings"
"github.com/micro-editor/tcell/v2")
type Event interface { Name() string}
// RawEvent is simply an escape code// We allow users to directly bind escape codes// to get around some of a limitations of terminalstype RawEvent struct { esc string}
func (r RawEvent) Name() string { return r.esc}
// KeyEvent is a key event containing a key code,// some possible modifiers (alt, ctrl, etc...) and// a rune if it was simply a character press// Note: to be compatible with tcell events,// for ctrl keys r=codetype KeyEvent struct { code tcell.Key mod tcell.ModMask r rune any bool}
func metaToAlt(mod tcell.ModMask) tcell.ModMask { if mod&tcell.ModMeta != 0 { mod &= ^tcell.ModMeta mod |= tcell.ModAlt } return mod}
func keyEvent(e *tcell.EventKey) KeyEvent { ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), } if e.Key() == tcell.KeyRune { ke.r = e.Rune() } return ke}
func (k KeyEvent) Name() string { if k.any { return "<any>" } s := "" m := []string{} if k.mod&tcell.ModShift != 0 { m = append(m, "Shift") } if k.mod&tcell.ModAlt != 0 { m = append(m, "Alt") } if k.mod&tcell.ModMeta != 0 { m = append(m, "Meta") } if k.mod&tcell.ModCtrl != 0 { m = append(m, "Ctrl") }
ok := false if s, ok = tcell.KeyNames[k.code]; !ok { if k.code == tcell.KeyRune { s = string(k.r) } else { s = fmt.Sprintf("Key[%d]", k.code) } } if len(m) != 0 { if k.mod&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") { s = s[5:] if len(s) == 1 { s = strings.ToLower(s) } } return fmt.Sprintf("%s-%s", strings.Join(m, "-"), s) } return s}
// A KeySequence defines a list of consecutive// events. All events in the sequence must be KeyEvents// or MouseEvents.type KeySequenceEvent struct { keys []Event}
func (k KeySequenceEvent) Name() string { buf := bytes.Buffer{} for _, e := range k.keys { buf.WriteByte('<') buf.WriteString(e.Name()) buf.WriteByte('>') } return buf.String()}
type MouseState int
const ( MousePress = iota MouseDrag MouseRelease)
// MouseEvent is a mouse event with a mouse button and// any possible key modifierstype MouseEvent struct { btn tcell.ButtonMask mod tcell.ModMask state MouseState}
func (m MouseEvent) Name() string { mod := "" if m.mod&tcell.ModShift != 0 { mod = "Shift-" } if m.mod&tcell.ModAlt != 0 { mod = "Alt-" } if m.mod&tcell.ModMeta != 0 { mod = "Meta-" } if m.mod&tcell.ModCtrl != 0 { mod = "Ctrl-" }
state := "" switch m.state { case MouseDrag: state = "Drag" case MouseRelease: state = "Release" }
for k, v := range mouseEvents { if v == m.btn { return fmt.Sprintf("%s%s%s", mod, k, state) } } return ""}
// ConstructEvent takes a tcell event and returns a micro// event. Note that tcell events can't express certain// micro events such as key sequences. This function is// mostly used for debugging/raw panes or constructing// intermediate micro events while parsing a sequence.func ConstructEvent(event tcell.Event) (Event, error) { switch e := event.(type) { case *tcell.EventKey: return keyEvent(e), nil case *tcell.EventRaw: return RawEvent{ esc: e.EscSeq(), }, nil case *tcell.EventMouse: return MouseEvent{ btn: e.Buttons(), mod: metaToAlt(e.Modifiers()), }, nil } return nil, errors.New("No micro event equivalent")}
// A Handler will take a tcell event and execute it// appropriatelytype Handler interface { HandleEvent(tcell.Event) HandleCommand(string)}