mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-18 16:45:38 -05:00
Extend support for alt key chords
"alt-" with any case-sensitive character is allowed
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -230,7 +231,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) []byte {
|
||||
}
|
||||
|
||||
retries := 0
|
||||
if c == ESC || nonblock {
|
||||
if c == ESC.Int() || nonblock {
|
||||
retries = r.escDelay / escPollInterval
|
||||
}
|
||||
buffer = append(buffer, byte(c))
|
||||
@@ -245,7 +246,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) []byte {
|
||||
continue
|
||||
}
|
||||
break
|
||||
} else if c == ESC && pc != c {
|
||||
} else if c == ESC.Int() && pc != c {
|
||||
retries = r.escDelay / escPollInterval
|
||||
} else {
|
||||
retries = 0
|
||||
@@ -278,11 +279,11 @@ func (r *LightRenderer) GetChar() Event {
|
||||
}()
|
||||
|
||||
switch r.buffer[0] {
|
||||
case CtrlC:
|
||||
case CtrlC.Byte():
|
||||
return Event{CtrlC, 0, nil}
|
||||
case CtrlG:
|
||||
case CtrlG.Byte():
|
||||
return Event{CtrlG, 0, nil}
|
||||
case CtrlQ:
|
||||
case CtrlQ.Byte():
|
||||
return Event{CtrlQ, 0, nil}
|
||||
case 127:
|
||||
return Event{BSpace, 0, nil}
|
||||
@@ -296,7 +297,7 @@ func (r *LightRenderer) GetChar() Event {
|
||||
return Event{CtrlCaret, 0, nil}
|
||||
case 31:
|
||||
return Event{CtrlSlash, 0, nil}
|
||||
case ESC:
|
||||
case ESC.Byte():
|
||||
ev := r.escSequence(&sz)
|
||||
// Second chance
|
||||
if ev.Type == Invalid {
|
||||
@@ -307,8 +308,8 @@ func (r *LightRenderer) GetChar() Event {
|
||||
}
|
||||
|
||||
// CTRL-A ~ CTRL-Z
|
||||
if r.buffer[0] <= CtrlZ {
|
||||
return Event{int(r.buffer[0]), 0, nil}
|
||||
if r.buffer[0] <= CtrlZ.Byte() {
|
||||
return Event{EventType(r.buffer[0]), 0, nil}
|
||||
}
|
||||
char, rsz := utf8.DecodeRune(r.buffer)
|
||||
if char == utf8.RuneError {
|
||||
@@ -331,26 +332,16 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
||||
|
||||
*sz = 2
|
||||
if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
|
||||
return Event{int(CtrlAltA + r.buffer[1] - 1), 0, nil}
|
||||
return CtrlAltKey(rune(r.buffer[1] + 'a' - 1))
|
||||
}
|
||||
alt := false
|
||||
if len(r.buffer) > 2 && r.buffer[1] == ESC {
|
||||
if len(r.buffer) > 2 && r.buffer[1] == ESC.Byte() {
|
||||
r.buffer = r.buffer[1:]
|
||||
alt = true
|
||||
}
|
||||
switch r.buffer[1] {
|
||||
case ESC:
|
||||
case ESC.Byte():
|
||||
return Event{ESC, 0, nil}
|
||||
case ' ':
|
||||
return Event{AltSpace, 0, nil}
|
||||
case '/':
|
||||
return Event{AltSlash, 0, nil}
|
||||
case 'b':
|
||||
return Event{AltB, 0, nil}
|
||||
case 'd':
|
||||
return Event{AltD, 0, nil}
|
||||
case 'f':
|
||||
return Event{AltF, 0, nil}
|
||||
case 127:
|
||||
return Event{AltBS, 0, nil}
|
||||
case '[', 'O':
|
||||
@@ -518,11 +509,11 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
||||
} // r.buffer[2]
|
||||
} // r.buffer[2]
|
||||
} // r.buffer[1]
|
||||
if r.buffer[1] >= 'a' && r.buffer[1] <= 'z' {
|
||||
return Event{AltA + int(r.buffer[1]) - 'a', 0, nil}
|
||||
}
|
||||
if r.buffer[1] >= '0' && r.buffer[1] <= '9' {
|
||||
return Event{Alt0 + int(r.buffer[1]) - '0', 0, nil}
|
||||
rest := bytes.NewBuffer(r.buffer[1:])
|
||||
c, size, err := rest.ReadRune()
|
||||
if err == nil {
|
||||
*sz = 1 + size
|
||||
return AltKey(c)
|
||||
}
|
||||
return Event{Invalid, 0, nil}
|
||||
}
|
||||
|
||||
@@ -226,65 +226,65 @@ func (r *FullscreenRenderer) GetChar() Event {
|
||||
alt := (mods & tcell.ModAlt) > 0
|
||||
shift := (mods & tcell.ModShift) > 0
|
||||
altShift := alt && shift
|
||||
keyfn := func(r rune) int {
|
||||
keyfn := func(r rune) Event {
|
||||
if alt {
|
||||
return CtrlAltA - 'a' + int(r)
|
||||
return CtrlAltKey(r)
|
||||
}
|
||||
return CtrlA - 'a' + int(r)
|
||||
return EventType(CtrlA.Int() - 'a' + int(r)).AsEvent()
|
||||
}
|
||||
switch ev.Key() {
|
||||
case tcell.KeyCtrlA:
|
||||
return Event{keyfn('a'), 0, nil}
|
||||
return keyfn('a')
|
||||
case tcell.KeyCtrlB:
|
||||
return Event{keyfn('b'), 0, nil}
|
||||
return keyfn('b')
|
||||
case tcell.KeyCtrlC:
|
||||
return Event{keyfn('c'), 0, nil}
|
||||
return keyfn('c')
|
||||
case tcell.KeyCtrlD:
|
||||
return Event{keyfn('d'), 0, nil}
|
||||
return keyfn('d')
|
||||
case tcell.KeyCtrlE:
|
||||
return Event{keyfn('e'), 0, nil}
|
||||
return keyfn('e')
|
||||
case tcell.KeyCtrlF:
|
||||
return Event{keyfn('f'), 0, nil}
|
||||
return keyfn('f')
|
||||
case tcell.KeyCtrlG:
|
||||
return Event{keyfn('g'), 0, nil}
|
||||
return keyfn('g')
|
||||
case tcell.KeyCtrlH:
|
||||
return Event{keyfn('h'), 0, nil}
|
||||
return keyfn('h')
|
||||
case tcell.KeyCtrlI:
|
||||
return Event{keyfn('i'), 0, nil}
|
||||
return keyfn('i')
|
||||
case tcell.KeyCtrlJ:
|
||||
return Event{keyfn('j'), 0, nil}
|
||||
return keyfn('j')
|
||||
case tcell.KeyCtrlK:
|
||||
return Event{keyfn('k'), 0, nil}
|
||||
return keyfn('k')
|
||||
case tcell.KeyCtrlL:
|
||||
return Event{keyfn('l'), 0, nil}
|
||||
return keyfn('l')
|
||||
case tcell.KeyCtrlM:
|
||||
return Event{keyfn('m'), 0, nil}
|
||||
return keyfn('m')
|
||||
case tcell.KeyCtrlN:
|
||||
return Event{keyfn('n'), 0, nil}
|
||||
return keyfn('n')
|
||||
case tcell.KeyCtrlO:
|
||||
return Event{keyfn('o'), 0, nil}
|
||||
return keyfn('o')
|
||||
case tcell.KeyCtrlP:
|
||||
return Event{keyfn('p'), 0, nil}
|
||||
return keyfn('p')
|
||||
case tcell.KeyCtrlQ:
|
||||
return Event{keyfn('q'), 0, nil}
|
||||
return keyfn('q')
|
||||
case tcell.KeyCtrlR:
|
||||
return Event{keyfn('r'), 0, nil}
|
||||
return keyfn('r')
|
||||
case tcell.KeyCtrlS:
|
||||
return Event{keyfn('s'), 0, nil}
|
||||
return keyfn('s')
|
||||
case tcell.KeyCtrlT:
|
||||
return Event{keyfn('t'), 0, nil}
|
||||
return keyfn('t')
|
||||
case tcell.KeyCtrlU:
|
||||
return Event{keyfn('u'), 0, nil}
|
||||
return keyfn('u')
|
||||
case tcell.KeyCtrlV:
|
||||
return Event{keyfn('v'), 0, nil}
|
||||
return keyfn('v')
|
||||
case tcell.KeyCtrlW:
|
||||
return Event{keyfn('w'), 0, nil}
|
||||
return keyfn('w')
|
||||
case tcell.KeyCtrlX:
|
||||
return Event{keyfn('x'), 0, nil}
|
||||
return keyfn('x')
|
||||
case tcell.KeyCtrlY:
|
||||
return Event{keyfn('y'), 0, nil}
|
||||
return keyfn('y')
|
||||
case tcell.KeyCtrlZ:
|
||||
return Event{keyfn('z'), 0, nil}
|
||||
return keyfn('z')
|
||||
case tcell.KeyCtrlSpace:
|
||||
return Event{CtrlSpace, 0, nil}
|
||||
case tcell.KeyCtrlBackslash:
|
||||
@@ -389,18 +389,7 @@ func (r *FullscreenRenderer) GetChar() Event {
|
||||
case tcell.KeyRune:
|
||||
r := ev.Rune()
|
||||
if alt {
|
||||
switch r {
|
||||
case ' ':
|
||||
return Event{AltSpace, 0, nil}
|
||||
case '/':
|
||||
return Event{AltSlash, 0, nil}
|
||||
}
|
||||
if r >= 'a' && r <= 'z' {
|
||||
return Event{AltA + int(r) - 'a', 0, nil}
|
||||
}
|
||||
if r >= '0' && r <= '9' {
|
||||
return Event{Alt0 + int(r) - '0', 0, nil}
|
||||
}
|
||||
return AltKey(r)
|
||||
}
|
||||
return Event{Rune, r, nil}
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
)
|
||||
|
||||
// Types of user action
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
Rune = iota
|
||||
Rune EventType = iota
|
||||
|
||||
CtrlA
|
||||
CtrlB
|
||||
@@ -89,8 +91,6 @@ const (
|
||||
Change
|
||||
BackwardEOF
|
||||
|
||||
AltSpace
|
||||
AltSlash
|
||||
AltBS
|
||||
|
||||
AltUp
|
||||
@@ -103,20 +103,38 @@ const (
|
||||
AltSLeft
|
||||
AltSRight
|
||||
|
||||
Alt0
|
||||
Alt
|
||||
CtrlAlt
|
||||
)
|
||||
|
||||
const ( // Reset iota
|
||||
AltA = Alt0 + 'a' - '0' + iota
|
||||
AltB
|
||||
AltC
|
||||
AltD
|
||||
AltE
|
||||
AltF
|
||||
AltZ = AltA + 'z' - 'a'
|
||||
CtrlAltA = AltZ + 1
|
||||
CtrlAltM = CtrlAltA + 'm' - 'a'
|
||||
)
|
||||
func (t EventType) AsEvent() Event {
|
||||
return Event{t, 0, nil}
|
||||
}
|
||||
|
||||
func (t EventType) Int() int {
|
||||
return int(t)
|
||||
}
|
||||
|
||||
func (t EventType) Byte() byte {
|
||||
return byte(t)
|
||||
}
|
||||
|
||||
func (e Event) Comparable() Event {
|
||||
// Ignore MouseEvent pointer
|
||||
return Event{e.Type, e.Char, nil}
|
||||
}
|
||||
|
||||
func Key(r rune) Event {
|
||||
return Event{Rune, r, nil}
|
||||
}
|
||||
|
||||
func AltKey(r rune) Event {
|
||||
return Event{Alt, r, nil}
|
||||
}
|
||||
|
||||
func CtrlAltKey(r rune) Event {
|
||||
return Event{CtrlAlt, r, nil}
|
||||
}
|
||||
|
||||
const (
|
||||
doubleClickDuration = 500 * time.Millisecond
|
||||
@@ -251,7 +269,7 @@ type ColorTheme struct {
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Type int
|
||||
Type EventType
|
||||
Char rune
|
||||
MouseEvent *MouseEvent
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user