1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-03 13:21:56 +02:00
2022-03-17 19:13:40 +11:00

305 lines
9.0 KiB
Go

// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gocui
import (
"strings"
"github.com/gdamore/tcell/v2"
)
// Key represents special keys or keys combinations.
type Key tcell.Key
// Modifier allows to define special keys combinations. They can be used
// in combination with Keys or Runes when a new keybinding is defined.
type Modifier tcell.ModMask
// Keybidings are used to link a given key-press event with a handler.
type keybinding struct {
viewName string
contexts []string
key Key
ch rune
mod Modifier
handler func(*Gui, *View) error
}
// Parse takes the input string and extracts the keybinding.
// Returns a Key / rune, a Modifier and an error.
func Parse(input string) (interface{}, Modifier, error) {
if len(input) == 1 {
_, r, err := getKey(rune(input[0]))
if err != nil {
return nil, ModNone, err
}
return r, ModNone, nil
}
var modifier Modifier
cleaned := make([]string, 0)
tokens := strings.Split(input, "+")
for _, t := range tokens {
normalized := strings.Title(strings.ToLower(t))
if t == "Alt" {
modifier = ModAlt
continue
}
cleaned = append(cleaned, normalized)
}
key, exist := translate[strings.Join(cleaned, "")]
if !exist {
return nil, ModNone, ErrNoSuchKeybind
}
return key, modifier, nil
}
// ParseAll takes an array of strings and returns a map of all keybindings.
func ParseAll(input []string) (map[interface{}]Modifier, error) {
ret := make(map[interface{}]Modifier)
for _, i := range input {
k, m, err := Parse(i)
if err != nil {
return ret, err
}
ret[k] = m
}
return ret, nil
}
// MustParse takes the input string and returns a Key / rune and a Modifier.
// It will panic if any error occured.
func MustParse(input string) (interface{}, Modifier) {
k, m, err := Parse(input)
if err != nil {
panic(err)
}
return k, m
}
// MustParseAll takes an array of strings and returns a map of all keybindings.
// It will panic if any error occured.
func MustParseAll(input []string) map[interface{}]Modifier {
result, err := ParseAll(input)
if err != nil {
panic(err)
}
return result
}
// newKeybinding returns a new Keybinding object.
func newKeybinding(viewname string, contexts []string, key Key, ch rune, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {
kb = &keybinding{
viewName: viewname,
contexts: contexts,
key: key,
ch: ch,
mod: mod,
handler: handler,
}
return kb
}
func eventMatchesKey(ev *GocuiEvent, key interface{}) bool {
// assuming ModNone for now
if Modifier(ev.Mod) != ModNone {
return false
}
k, ch, err := getKey(key)
if err != nil {
return false
}
return k == Key(ev.Key) && ch == ev.Ch
}
// matchKeypress returns if the keybinding matches the keypress.
func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
return kb.key == key && kb.ch == ch && kb.mod == mod
}
// translations for strings to keys
var translate = map[string]Key{
"F1": KeyF1,
"F2": KeyF2,
"F3": KeyF3,
"F4": KeyF4,
"F5": KeyF5,
"F6": KeyF6,
"F7": KeyF7,
"F8": KeyF8,
"F9": KeyF9,
"F10": KeyF10,
"F11": KeyF11,
"F12": KeyF12,
"Insert": KeyInsert,
"Delete": KeyDelete,
"Home": KeyHome,
"End": KeyEnd,
"Pgup": KeyPgup,
"Pgdn": KeyPgdn,
"ArrowUp": KeyArrowUp,
"ArrowDown": KeyArrowDown,
"ArrowLeft": KeyArrowLeft,
"ArrowRight": KeyArrowRight,
"CtrlTilde": KeyCtrlTilde,
"Ctrl2": KeyCtrl2,
"CtrlSpace": KeyCtrlSpace,
"CtrlA": KeyCtrlA,
"CtrlB": KeyCtrlB,
"CtrlC": KeyCtrlC,
"CtrlD": KeyCtrlD,
"CtrlE": KeyCtrlE,
"CtrlF": KeyCtrlF,
"CtrlG": KeyCtrlG,
"Backspace": KeyBackspace,
"CtrlH": KeyCtrlH,
"Tab": KeyTab,
"BackTab": KeyBacktab,
"CtrlI": KeyCtrlI,
"CtrlJ": KeyCtrlJ,
"CtrlK": KeyCtrlK,
"CtrlL": KeyCtrlL,
"Enter": KeyEnter,
"CtrlM": KeyCtrlM,
"CtrlN": KeyCtrlN,
"CtrlO": KeyCtrlO,
"CtrlP": KeyCtrlP,
"CtrlQ": KeyCtrlQ,
"CtrlR": KeyCtrlR,
"CtrlS": KeyCtrlS,
"CtrlT": KeyCtrlT,
"CtrlU": KeyCtrlU,
"CtrlV": KeyCtrlV,
"CtrlW": KeyCtrlW,
"CtrlX": KeyCtrlX,
"CtrlY": KeyCtrlY,
"CtrlZ": KeyCtrlZ,
"Esc": KeyEsc,
"CtrlLsqBracket": KeyCtrlLsqBracket,
"Ctrl3": KeyCtrl3,
"Ctrl4": KeyCtrl4,
"CtrlBackslash": KeyCtrlBackslash,
"Ctrl5": KeyCtrl5,
"CtrlRsqBracket": KeyCtrlRsqBracket,
"Ctrl6": KeyCtrl6,
"Ctrl7": KeyCtrl7,
"CtrlSlash": KeyCtrlSlash,
"CtrlUnderscore": KeyCtrlUnderscore,
"Space": KeySpace,
"Backspace2": KeyBackspace2,
"Ctrl8": KeyCtrl8,
"Mouseleft": MouseLeft,
"Mousemiddle": MouseMiddle,
"Mouseright": MouseRight,
"Mouserelease": MouseRelease,
"MousewheelUp": MouseWheelUp,
"MousewheelDown": MouseWheelDown,
}
// Special keys.
const (
KeyF1 Key = Key(tcell.KeyF1)
KeyF2 = Key(tcell.KeyF2)
KeyF3 = Key(tcell.KeyF3)
KeyF4 = Key(tcell.KeyF4)
KeyF5 = Key(tcell.KeyF5)
KeyF6 = Key(tcell.KeyF6)
KeyF7 = Key(tcell.KeyF7)
KeyF8 = Key(tcell.KeyF8)
KeyF9 = Key(tcell.KeyF9)
KeyF10 = Key(tcell.KeyF10)
KeyF11 = Key(tcell.KeyF11)
KeyF12 = Key(tcell.KeyF12)
KeyInsert = Key(tcell.KeyInsert)
KeyDelete = Key(tcell.KeyDelete)
KeyHome = Key(tcell.KeyHome)
KeyEnd = Key(tcell.KeyEnd)
KeyPgdn = Key(tcell.KeyPgDn)
KeyPgup = Key(tcell.KeyPgUp)
KeyArrowUp = Key(tcell.KeyUp)
KeyArrowDown = Key(tcell.KeyDown)
KeyArrowLeft = Key(tcell.KeyLeft)
KeyArrowRight = Key(tcell.KeyRight)
)
// Keys combinations.
const (
KeyCtrlTilde = Key(tcell.KeyF64) // arbitrary assignment
KeyCtrlSpace = Key(tcell.KeyCtrlSpace)
KeyCtrlA = Key(tcell.KeyCtrlA)
KeyCtrlB = Key(tcell.KeyCtrlB)
KeyCtrlC = Key(tcell.KeyCtrlC)
KeyCtrlD = Key(tcell.KeyCtrlD)
KeyCtrlE = Key(tcell.KeyCtrlE)
KeyCtrlF = Key(tcell.KeyCtrlF)
KeyCtrlG = Key(tcell.KeyCtrlG)
KeyBackspace = Key(tcell.KeyBackspace)
KeyCtrlH = Key(tcell.KeyCtrlH)
KeyTab = Key(tcell.KeyTab)
KeyBacktab = Key(tcell.KeyBacktab)
KeyCtrlI = Key(tcell.KeyCtrlI)
KeyCtrlJ = Key(tcell.KeyCtrlJ)
KeyCtrlK = Key(tcell.KeyCtrlK)
KeyCtrlL = Key(tcell.KeyCtrlL)
KeyEnter = Key(tcell.KeyEnter)
KeyCtrlM = Key(tcell.KeyCtrlM)
KeyCtrlN = Key(tcell.KeyCtrlN)
KeyCtrlO = Key(tcell.KeyCtrlO)
KeyCtrlP = Key(tcell.KeyCtrlP)
KeyCtrlQ = Key(tcell.KeyCtrlQ)
KeyCtrlR = Key(tcell.KeyCtrlR)
KeyCtrlS = Key(tcell.KeyCtrlS)
KeyCtrlT = Key(tcell.KeyCtrlT)
KeyCtrlU = Key(tcell.KeyCtrlU)
KeyCtrlV = Key(tcell.KeyCtrlV)
KeyCtrlW = Key(tcell.KeyCtrlW)
KeyCtrlX = Key(tcell.KeyCtrlX)
KeyCtrlY = Key(tcell.KeyCtrlY)
KeyCtrlZ = Key(tcell.KeyCtrlZ)
KeyEsc = Key(tcell.KeyEscape)
KeyCtrlUnderscore = Key(tcell.KeyCtrlUnderscore)
KeySpace = Key(32)
KeyBackspace2 = Key(tcell.KeyBackspace2)
KeyCtrl8 = Key(tcell.KeyBackspace2) // same key as in termbox-go
// The following assignments were used in termbox implementation.
// In tcell, these are not keys per se. But in gocui we have them
// mapped to the keys so we have to use placeholder keys.
KeyAltEnter = Key(tcell.KeyF64) // arbitrary assignments
MouseLeft = Key(tcell.KeyF63)
MouseRight = Key(tcell.KeyF62)
MouseMiddle = Key(tcell.KeyF61)
MouseRelease = Key(tcell.KeyF60)
MouseWheelUp = Key(tcell.KeyF59)
MouseWheelDown = Key(tcell.KeyF58)
MouseWheelLeft = Key(tcell.KeyF57)
MouseWheelRight = Key(tcell.KeyF56)
KeyCtrl2 = Key(tcell.KeyNUL) // termbox defines theses
KeyCtrl3 = Key(tcell.KeyEscape)
KeyCtrl4 = Key(tcell.KeyCtrlBackslash)
KeyCtrl5 = Key(tcell.KeyCtrlRightSq)
KeyCtrl6 = Key(tcell.KeyCtrlCarat)
KeyCtrl7 = Key(tcell.KeyCtrlUnderscore)
KeyCtrlSlash = Key(tcell.KeyCtrlUnderscore)
KeyCtrlRsqBracket = Key(tcell.KeyCtrlRightSq)
KeyCtrlBackslash = Key(tcell.KeyCtrlBackslash)
KeyCtrlLsqBracket = Key(tcell.KeyCtrlLeftSq)
)
// Modifiers.
const (
ModNone Modifier = Modifier(0)
ModAlt = Modifier(tcell.ModAlt)
ModMotion = Modifier(2) // just picking an arbitrary number here that doesn't clash with tcell.ModAlt
// ModCtrl doesn't work with keyboard keys. Use CtrlKey in Key and ModNone. This is was for mouse clicks only (tcell.v1)
// ModCtrl = Modifier(tcell.ModCtrl)
)