mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-03 13:21:56 +02:00
305 lines
9.0 KiB
Go
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)
|
|
)
|