m/fzf
1
0
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:
Junegunn Choi
2020-12-30 01:59:18 +09:00
parent 0de7ab18f6
commit 7f8e0dbc40
8 changed files with 318 additions and 306 deletions

View File

@@ -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}
}

View File

@@ -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}

View File

@@ -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
}