summaryrefslogtreecommitdiff
path: root/src/tui
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2020-12-30 01:59:18 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2020-12-30 18:39:17 +0900
commit7f8e0dbc408eff786865d0e2d9e3c62ec3ed4776 (patch)
treedeeac2dc561a2ccd5bf444f4180abb43bff060be /src/tui
parent0de7ab18f64db7838c8ca06d08188f976cbfdbb4 (diff)
downloadfzf-7f8e0dbc408eff786865d0e2d9e3c62ec3ed4776.tar.gz
Extend support for alt key chords
"alt-" with any case-sensitive character is allowed
Diffstat (limited to 'src/tui')
-rw-r--r--src/tui/light.go43
-rw-r--r--src/tui/tcell.go71
-rw-r--r--src/tui/tui.go50
3 files changed, 81 insertions, 83 deletions
diff --git a/src/tui/light.go b/src/tui/light.go
index 4f50d687..9c48b465 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -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}
}
diff --git a/src/tui/tcell.go b/src/tui/tcell.go
index 16d3151a..938c1ba0 100644
--- a/src/tui/tcell.go
+++ b/src/tui/tcell.go
@@ -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}
diff --git a/src/tui/tui.go b/src/tui/tui.go
index edbc9a14..cc9c7f67 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -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
}